// -*- 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