// -*- C++ -*- /* Heap Layers: An Extensible Memory Allocation Infrastructure Copyright (C) 2000-2020 by Emery Berger http://www.emeryberger.com emery@cs.umass.edu Heap Layers is distributed under the terms of the Apache 2.0 license. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 */ /** * @file segheap.h * @brief Definition of SegHeap. */ #ifndef HL_SEGHEAP_H #define HL_SEGHEAP_H /** * @class SegHeap * @brief A segregated-fits collection of (homogeneous) heaps. * @author Emery Berger * * Note that one extra heap is used for objects that are "too big". * * @param NumBins The number of bins (subheaps). * @param getSizeClass Function to compute size class from size. * @param getClassMaxSize Function to compute the largest size for a given size class. * @param LittleHeap The subheap class. * @param BigHeap The parent class, used for "big" objects. * * Example:
* * int myFunc (size_t sz); // The size-to-class function.
* size_t myFunc2 (int); // The class-to-size function.

* // The heap. Use freelists for these small objects,
* // but defer to malloc for large objects.

* * SegHeap<4, myFunc, myFunc2, freelistHeap, MallocHeap> mySegHeap; * **/ #include #include "utility/gcd.h" namespace HL { template class SegHeap : public LittleHeap { public: enum { Alignment = gcd::VALUE }; inline SegHeap() : _memoryHeld (0), _maxObjectSize (getClassMaxSize(NumBins - 1)) { for (int i = 0; i < NUM_ULONGS; i++) { binmap[i] = 0; } } inline size_t getMemoryHeld() const { return _memoryHeld; } size_t getSize (void * ptr) { return LittleHeap::getSize (ptr); } inline void * malloc (const size_t sz) { void * ptr = nullptr; if (sz > _maxObjectSize) { goto GET_MEMORY; } { const auto sc = getSizeClass(sz); assert (sc >= 0); assert (sc < NumBins); auto idx = sc; auto block = idx2block (idx); unsigned long map = binmap[block]; unsigned long bit = idx2bit (idx); for (;;) { if (bit > map || bit == 0) { do { if (++block >= NUM_ULONGS) { goto GET_MEMORY; // return bigheap.malloc (sz); } } while ( (map = binmap[block]) == 0); idx = block << SHIFTS_PER_ULONG; bit = 1; } while ((bit & map) == 0) { bit <<= 1; assert(bit != 0); idx++; } assert (idx < NumBins); ptr = myLittleHeap[idx].malloc (sz); if (ptr == NULL) { binmap[block] = map &= ~bit; // Write through idx++; bit <<= 1; } else { _memoryHeld -= sz; return ptr; } } } GET_MEMORY: if (ptr == NULL) { // There was no free memory in any of the bins. // Get some memory. ptr = bigheap.malloc (sz); } return ptr; } inline void free (void * ptr) { // printf ("Free: %x (%d bytes)\n", ptr, getSize(ptr)); const auto objectSize = getSize(ptr); // was bigheap.getSize(ptr) if (objectSize > _maxObjectSize) { bigheap.free (ptr); } else { auto objectSizeClass = getSizeClass(objectSize); assert (objectSizeClass >= 0); assert (objectSizeClass < NumBins); // Put the freed object into the right sizeclass heap. assert (getClassMaxSize(objectSizeClass) >= objectSize); #if 1 while (getClassMaxSize(objectSizeClass) > objectSize) { objectSizeClass--; } #endif assert (getClassMaxSize(objectSizeClass) <= objectSize); if (objectSizeClass > 0) { assert (objectSize >= getClassMaxSize(objectSizeClass - 1)); } myLittleHeap[objectSizeClass].free (ptr); mark_bin (objectSizeClass); _memoryHeld += objectSize; } } void clear() { for (auto i = 0; i < NumBins; i++) { myLittleHeap[i].clear(); } for (auto j = 0; j < NUM_ULONGS; j++) { binmap[j] = 0; } bigheap.clear(); _memoryHeld = 0; } private: enum { BITS_PER_ULONG = sizeof(unsigned long) * 8 }; enum { SHIFTS_PER_ULONG = (BITS_PER_ULONG == 32) ? 5 : 6 }; enum { MAX_BITS = (NumBins + BITS_PER_ULONG - 1) & ~(BITS_PER_ULONG - 1) }; private: static inline int idx2block (int i) { int blk = i >> SHIFTS_PER_ULONG; assert (blk < NUM_ULONGS); assert (blk >= 0); return blk; } static inline unsigned long idx2bit (int i) { unsigned long bit = ((1U << ((i) & ((1U << SHIFTS_PER_ULONG)-1)))); return bit; } protected: BigHeap bigheap; enum { NUM_ULONGS = MAX_BITS / BITS_PER_ULONG }; unsigned long binmap[NUM_ULONGS]; inline int get_binmap (int i) const { return binmap[i >> SHIFTS_PER_ULONG] & idx2bit(i); } inline void mark_bin (int i) { binmap[i >> SHIFTS_PER_ULONG] |= idx2bit(i); } inline void unmark_bin (int i) { binmap[i >> SHIFTS_PER_ULONG] &= ~(idx2bit(i)); } size_t _memoryHeld; const size_t _maxObjectSize; // The little heaps. LittleHeap myLittleHeap[NumBins]; }; } #endif