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))