add clang flags so that libcds will be compiled with llvm pass
[c11concurrency-benchmarks.git] / silo / allocator.h
1 #ifndef _NDB_ALLOCATOR_H_
2 #define _NDB_ALLOCATOR_H_
3
4 #include <cstdint>
5 #include <iterator>
6 #include <mutex>
7
8 #include "util.h"
9 #include "core.h"
10 #include "macros.h"
11 #include "spinlock.h"
12
13 class allocator {
14 public:
15
16   // our allocator doesn't let allocations exceed maxpercore over a single core
17   //
18   // Initialize can be called many times- but only the first call has effect.
19   //
20   // w/o calling Initialize(), behavior for this class is undefined
21   static void Initialize(size_t ncpus, size_t maxpercore);
22
23   static void DumpStats();
24
25   // returns an arena linked-list
26   static void *
27   AllocateArenas(size_t cpu, size_t sz);
28
29   // allocates nhugepgs * hugepagesize contiguous bytes from CPU's region and
30   // returns the raw, unmanaged pointer.
31   //
32   // Note that memory returned from here cannot be released back to the
33   // allocator, so this should only be used for data structures which live
34   // throughput the duration of the system (ie log buffers)
35   static void *
36   AllocateUnmanaged(size_t cpu, size_t nhugepgs);
37
38   static void
39   ReleaseArenas(void **arenas);
40
41   static const size_t LgAllocAlignment = 4; // all allocations aligned to 2^4 = 16
42   static const size_t AllocAlignment = 1 << LgAllocAlignment;
43   static const size_t MAX_ARENAS = 32;
44
45   static inline std::pair<size_t, size_t>
46   ArenaSize(size_t sz)
47   {
48     const size_t allocsz = util::round_up<size_t, LgAllocAlignment>(sz);
49     const size_t arena = allocsz / AllocAlignment - 1;
50     return std::make_pair(allocsz, arena);
51   }
52
53   // slow, but only needs to be called on initialization
54   static void
55   FaultRegion(size_t cpu);
56
57   // returns true if managed by this allocator, false otherwise
58   static inline bool
59   ManagesPointer(const void *p)
60   {
61     return p >= g_memstart && p < g_memend;
62   }
63
64   // assumes p is managed by this allocator- returns the CPU from which this pointer
65   // was allocated
66   static inline size_t
67   PointerToCpu(const void *p)
68   {
69     ALWAYS_ASSERT(p >= g_memstart);
70     ALWAYS_ASSERT(p < g_memend);
71     const size_t ret =
72       (reinterpret_cast<const char *>(p) -
73        reinterpret_cast<const char *>(g_memstart)) / g_maxpercore;
74     ALWAYS_ASSERT(ret < g_ncpus);
75     return ret;
76   }
77
78 #ifdef MEMCHECK_MAGIC
79   struct pgmetadata {
80     uint32_t unit_; // 0-indexed
81   } PACKED;
82
83   // returns nullptr if p is not managed, or has not been allocated yet.
84   // p does not have to be properly aligned
85   static const pgmetadata *
86   PointerToPgMetadata(const void *p);
87 #endif
88
89   static size_t
90   GetPageSize()
91   {
92     static const size_t sz = GetPageSizeImpl();
93     return sz;
94   }
95
96   static size_t
97   GetHugepageSize()
98   {
99     static const size_t sz = GetHugepageSizeImpl();
100     return sz;
101   }
102
103 private:
104   static size_t GetPageSizeImpl();
105   static size_t GetHugepageSizeImpl();
106   static bool UseMAdvWillNeed();
107
108   struct regionctx {
109     regionctx()
110       : region_begin(nullptr),
111         region_end(nullptr),
112         region_faulted(false)
113     {
114       NDB_MEMSET(arenas, 0, sizeof(arenas));
115     }
116     regionctx(const regionctx &) = delete;
117     regionctx(regionctx &&) = delete;
118     regionctx &operator=(const regionctx &) = delete;
119
120     // set by Initialize()
121     void *region_begin;
122     void *region_end;
123
124     bool region_faulted;
125
126     spinlock lock;
127     std::mutex fault_lock; // XXX: hacky
128     void *arenas[MAX_ARENAS];
129   };
130
131   // assumes caller has the regionctx lock held, and
132   // will release the lock.
133   static void *
134   AllocateUnmanagedWithLock(regionctx &pc, size_t nhugepgs);
135
136   // [g_memstart, g_memstart + ncpus * maxpercore) is the region of memory mmap()-ed
137   static void *g_memstart;
138   static void *g_memend; // g_memstart + ncpus * maxpercore
139   static size_t g_ncpus;
140   static size_t g_maxpercore;
141
142   static percore<regionctx> g_regions CACHE_ALIGNED;
143 };
144
145 #endif /* _NDB_ALLOCATOR_H_ */