20static constexpr size_t MINIMUM_HUGEPAGE = 2 * 1024 * 1024;
40 void* bump_alloc (
size_t size);
41 size_t grow_spans (
size_t needed,
bool preallocating);
42 size_t free_block ()
const;
44 size_t totalmem ()
const {
return totalmem_; }
46 char* memmap (
size_t size,
bool growsup);
47 char* remap (
void *addr,
size_t oldsize,
size_t size);
49 char *mmstart =
nullptr;
50 boost::atomic<uintptr_t> offset = 0;
51 boost::atomic<uintptr_t> mmsize = 0;
52 boost::atomic<MMSpan*> next =
nullptr;
54 boost::atomic<size_t> totalmem_ = 0;
55 boost::atomic<MMSpan*> spans_ =
nullptr;
60BumpAllocator::list_arenas (
ArenaList &arenas)
62 for (MMSpan *lspan = spans_; lspan; lspan = lspan->next)
63 arenas.
push_back ({ uintptr_t (lspan->mmstart), lspan->offset, lspan->mmsize });
67BumpAllocator::free_block ()
const
70 MMSpan *lspan = spans_;
71 while (lspan && lspan->next)
75 return lspan->mmsize - lspan->offset;
79BumpAllocator::grow_spans (
size_t needed,
bool preallocating)
81 const size_t entry_total = totalmem_;
83 if (entry_total < totalmem_)
86 warning (
"BumpAllocator: growing from within loft_alloc (total=%u): need=%d bytes\n", totalmem_ + 0, needed);
90 MMSpan *lspan = spans_;
91 while (lspan && lspan->next)
93 totalmem += lspan->mmsize;
98 const size_t oldsize = lspan->mmsize;
99 size_t newsize = oldsize * 2;
100 while (newsize < needed)
102 char *mmstart = remap (lspan->mmstart, oldsize, newsize);
103 if (mmstart == lspan->mmstart)
105 if (config_flags & PREFAULT_PAGES)
106 for (
size_t i = oldsize; i < newsize; i +=
PAGESIZE)
108 lspan->mmsize = newsize;
109 totalmem_ = totalmem + newsize;
110 VDEBUG (
"%s:%u: new-total=%dM: true\n", __func__, __LINE__, totalmem_ / (1024 * 1024));
111 return newsize - oldsize;
115 size_t mmsize = MINIMUM_HUGEPAGE;
116 while (mmsize < needed)
118 mmsize = MEM_ALIGN (mmsize, MINIMUM_HUGEPAGE);
119 char *mmstart = memmap (mmsize, !lspan);
122 VDEBUG (
"%s:%u: false\n", __func__, __LINE__);
125 for (
size_t i = 0; i < mmsize; i +=
PAGESIZE)
127 MMSpan *nspan =
new (mmstart) MMSpan();
128 nspan->offset = MEM_ALIGN (
sizeof (MMSpan), 64);
129 nspan->mmstart = mmstart;
130 nspan->mmsize = mmsize;
135 totalmem_ = totalmem + nspan->mmsize;
136 VDEBUG (
"%s:%u: new-total=%dM: true\n", __func__, __LINE__, totalmem_ / (1024 * 1024));
141BumpAllocator::remap (
void *addr,
size_t oldsize,
size_t size)
143 assert_return (MEM_ALIGN (size, MINIMUM_HUGEPAGE) == size,
nullptr);
146 char *memory = (
char*) mremap (addr, oldsize, size, 0, addr);
147 if (memory == MAP_FAILED)
149 VDEBUG (
"%s:%u: mremap: %p %d %d: %s\n", __func__, __LINE__, addr, oldsize, size, strerror (errno));
152 VDEBUG (
"%s:%u: mremap: %p %d %d: %p\n", __func__, __LINE__, addr, oldsize, size, memory);
153 if (madvise (memory, size, MADV_HUGEPAGE) < 0)
154 VDEBUG (
"%s: madvise(%p,%u,MADV_HUGEPAGE) failed: %s\n", __func__, memory, size, strerror (errno));
159BumpAllocator::memmap (
size_t size,
bool growsup)
161 assert_return (MEM_ALIGN (size, MINIMUM_HUGEPAGE) == size,
nullptr);
162 const int PROTECTION = PROT_READ | PROT_WRITE;
163 const int PRIVANON = MAP_PRIVATE | MAP_ANONYMOUS;
165 const bool anon_hugepages =
true;
166 const bool reserved_hugepages =
false;
169 void *addr =
nullptr;
170 const size_t g1 = 1024 * 1024 * 1024;
171 const size_t gigabytes =
sizeof (
size_t) <= 4 ? 3 * g1 : 256 * g1;
172 for (
size_t giga = gigabytes; giga >= 16 * 1024 * 1024; giga = giga >> 1)
173 if ((addr = mmap (
nullptr, giga, 0 * PROTECTION, PRIVANON, -1, 0)) != MAP_FAILED)
175 VDEBUG (
"%s:%d: addr-hint size=%uMB: %p\n", __FILE__, __LINE__, giga / (1024 * 1024), addr);
179 if (addr == MAP_FAILED)
184 if (reserved_hugepages)
186 memory = (
char*) mmap (addr, size, PROTECTION, PRIVANON | MAP_HUGETLB, -1, 0);
187 if (memory != MAP_FAILED)
189 VDEBUG (
"%s:%u: mmap: %p %d HUGETLB: %p\n", __func__, __LINE__, addr, size, memory);
192 VDEBUG (
"%s:%u: mmap: %p %d HUGETLB: %s\n", __func__, __LINE__, addr, size, strerror (errno));
196 size_t areasize =
size + MINIMUM_HUGEPAGE;
197 memory = (
char*) mmap (addr, areasize, PROTECTION, PRIVANON, -1, 0);
198 if (memory == MAP_FAILED)
200 VDEBUG (
"%s:%u: mmap: %p %d: %s\n", __func__, __LINE__, addr, areasize, strerror (errno));
203 VDEBUG (
"%s:%u: mmap: %p %d: %p\n", __func__, __LINE__, addr, areasize, memory);
206 size_t extra = MEM_ALIGN (start, MINIMUM_HUGEPAGE) - start;
207 if (extra && munmap (memory, extra) != 0)
208 VDEBUG (
"%s: munmap(%p,%u) failed: %s\n", __func__, memory, extra, strerror (errno));
212 extra = areasize -
size;
214 if (extra && munmap (memory + areasize, extra) != 0)
215 VDEBUG (
"%s: munmap(%p,%u) failed: %s\n", __func__, memory + areasize, extra, strerror (errno));
217 VDEBUG (
"%s:%u: mmap page-align: size=%d at: %p\n", __func__, __LINE__, size, memory);
220 if (anon_hugepages && madvise (memory, size, MADV_HUGEPAGE) < 0)
221 VDEBUG (
"%s: madvise(%p,%u,MADV_HUGEPAGE) failed: %s\n", __func__, memory, size, strerror (errno));
226BumpAllocator::bump_alloc (
size_t size)
229 for (MMSpan *span = spans_; span; span = span->next)
234 nmark = omark +
size;
235 if (nmark > span->mmsize)
238 while (!span->offset.compare_exchange_weak (omark, nmark));
241 span->mmsize - span->offset < config_watermark)
244 if (0 == config_lowmem_notified++)
251 return span->mmstart + omark;
255 grow_spans (size,
false);
257 return bump_alloc (size);
261static constexpr unsigned SMALL_BLOCK_LIMIT = 8192;
262static constexpr unsigned SMALL_BLOCK_BUCKETS = SMALL_BLOCK_LIMIT / 64;
263static constexpr unsigned NUMBER_OF_POWER2_BUCKETS =
sizeof (
uintptr_t) * 8;
264static constexpr unsigned NUMBER_OF_BUCKETS = NUMBER_OF_POWER2_BUCKETS + SMALL_BLOCK_BUCKETS;
268bucket_size (
unsigned index)
270 if (index < NUMBER_OF_POWER2_BUCKETS)
272 return (index - NUMBER_OF_POWER2_BUCKETS + 1) * 64;
276static inline unsigned
277bucket_index (
unsigned long long n)
280 if (n <= SMALL_BLOCK_LIMIT)
281 return NUMBER_OF_POWER2_BUCKETS + (n - 1) / 64;
282 constexpr unsigned CLZLL_BITS =
sizeof (0ull) * 8;
283 const unsigned upper_power2_shift = CLZLL_BITS - __builtin_clzll (n - 1);
284 return upper_power2_shift;
299 void do_free (
void *mem,
size_t size);
300 size_t count (
unsigned bucket_index,
const ArenaList &arenas);
304 boost::atomic<Block*> intr_ptr_ =
nullptr;
306 static_assert (
sizeof (Block) <= 64);
309 CANARY0 = 0xbe4da62f087c3519ull
311 bool maybeok (
const Block *block,
const ArenaList &arenas);
317LoftBuckets::do_alloc (
size_t size,
size_t align)
322 const unsigned bindex = bucket_index (size);
323 if (bindex >= NUMBER_OF_BUCKETS)
325 const size_t bsize = bucket_size (bindex);
326 auto block = buckets_[bindex].pop();
330 block = (Block*) bump_allocator.bump_alloc (bsize);
337LoftBuckets::do_free (
void *mem,
size_t size)
340 const unsigned bindex = bucket_index (size);
342 const size_t bsize = bucket_size (bindex);
344 auto block =
new (mem) Block();
345 buckets_[bindex].push (block);
349LoftBuckets::maybeok (
const Block *block,
const ArenaList &arenas)
356 bool contained =
false;
357 for (
const auto &a : arenas)
358 if (addr >= a.addr && addr < a.addr + a.
size)
365 block->canary0 == CANARY0)
371LoftBuckets::count (
unsigned bucket_index,
const ArenaList &arenas)
376 for (Block *block = buckets_[bucket_index].peek(); block; block = block->intr_ptr_.load())
377 if (maybeok (block, arenas))