[llvm-commits] CVS: poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp PoolAllocator.h
Chris Lattner
lattner at cs.uiuc.edu
Fri Mar 5 00:49:03 PST 2004
Changes in directory poolalloc/runtime/FL2Allocator:
FreeListAllocator.cpp updated: 1.7 -> 1.8
PoolAllocator.h updated: 1.2 -> 1.3
---
Log message:
The major change here is that we keep 4 freelists for objects of
size <= 16 bytes, size <= 64 bytes, size <= 256 bytes, and other. This
speeds up programs like ptrdist/bc a ***LOT*** by avoiding having to search
a giant freelist to allocate some mem
---
Diffs of the changes: (+123 -60)
Index: poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp
diff -u poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp:1.7 poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp:1.8
--- poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp:1.7 Thu Mar 4 22:39:09 2004
+++ poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp Fri Mar 5 00:44:55 2004
@@ -17,6 +17,7 @@
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
//===----------------------------------------------------------------------===//
//
@@ -26,9 +27,12 @@
#define PageSize (4*1024U)
-#define DEBUG(X)
//#define DEBUG(X) X
+#ifndef DEBUG
+#define DEBUG(X)
+#endif
+
// PoolSlab Structure - Hold multiple objects of the current node type.
// Invariants: FirstUnused <= UsedEnd
//
@@ -38,23 +42,24 @@
PoolSlab *Next;
public:
- static void create(PoolTy *Pool);
+ static void create(PoolTy *Pool, unsigned SizeHint);
void destroy();
PoolSlab *getNext() const { return Next; }
};
// create - Create a new (empty) slab and add it to the end of the Pools list.
-void PoolSlab::create(PoolTy *Pool) {
+void PoolSlab::create(PoolTy *Pool, unsigned SizeHint) {
unsigned Size = Pool->AllocSize;
Pool->AllocSize <<= 1;
+ Size = Size / SizeHint * SizeHint;
PoolSlab *PS = (PoolSlab*)malloc(Size);
// Add the body of the slab to the free list...
FreedNodeHeader *SlabBody = (FreedNodeHeader*)(PS+1);
SlabBody->Size = Size-sizeof(PoolSlab)-sizeof(FreedNodeHeader);
- SlabBody->NormalHeader.Next = Pool->FreeNodeList;
- Pool->FreeNodeList = SlabBody;
+ SlabBody->NormalHeader.Next = Pool->FreeNodeLists[LargeFreeList];
+ Pool->FreeNodeLists[LargeFreeList] = SlabBody;
// Add the slab to the list...
PS->Next = Pool->Slabs;
@@ -74,13 +79,11 @@
// poolinit - Initialize a pool descriptor to empty
//
-void poolinit(PoolTy *Pool) {
+void poolinit(PoolTy *Pool, unsigned DeclaredSize) {
assert(Pool && "Null pool pointer passed into poolinit!\n");
- Pool->Slabs = 0;
- Pool->FreeNodeList = 0;
- Pool->LargeArrays = 0;
+ memset(Pool, 0, sizeof(PoolTy));
Pool->AllocSize = PageSize;
-
+ Pool->DeclaredSize = DeclaredSize;
DEBUG(printf("init pool 0x%X\n", Pool));
}
@@ -89,8 +92,9 @@
void pooldestroy(PoolTy *Pool) {
assert(Pool && "Null pool pointer passed in to pooldestroy!\n");
- DEBUG(printf("destroy pool 0x%X NextAllocSize = %d\n", Pool,
- Pool->AllocSize));
+ DEBUG(printf("destroy pool 0x%X NextAllocSize = %d AvgObjSize = %d\n", Pool,
+ Pool->AllocSize,
+ Pool->NumObjects ? Pool->BytesAllocated/Pool->NumObjects : 0));
// Free all allocated slabs.
PoolSlab *PS = Pool->Slabs;
@@ -109,6 +113,19 @@
}
}
+static inline unsigned getSizeClass(unsigned NumBytes) {
+ if (NumBytes <= FreeListOneSize)
+ return NumBytes > FreeListZeroSize;
+ else
+ return 2 + (NumBytes > FreeListTwoSize);
+}
+
+static void AddNodeToFreeList(PoolTy *Pool, FreedNodeHeader *FreeNode) {
+ unsigned SizeClass = getSizeClass(FreeNode->Size);
+ FreeNode->NormalHeader.Next = Pool->FreeNodeLists[SizeClass];
+ Pool->FreeNodeLists[SizeClass] = FreeNode;
+}
+
void *poolalloc(PoolTy *Pool, unsigned NumBytes) {
// If a null pool descriptor is passed in, this is not a pool allocated data
@@ -117,23 +134,41 @@
if (NumBytes == 0) return 0;
NumBytes = (NumBytes+3) & ~3; // Round up to 4 bytes...
+ ++Pool->NumObjects;
+ Pool->BytesAllocated += NumBytes;
+
+ // Figure out which size class to start scanning from.
+ unsigned SizeClass = getSizeClass(NumBytes);
+
+ // Scan for a class that has entries!
+ while (SizeClass < 3 && Pool->FreeNodeLists[SizeClass] == 0)
+ ++SizeClass;
+
+ FreedNodeHeader *SizeClassFreeNodeList = Pool->FreeNodeLists[SizeClass];
+
// Fast path. In the common case, we can allocate a portion of the node at
// the front of the free list.
- if (FreedNodeHeader *FirstNode = Pool->FreeNodeList) {
+ if (FreedNodeHeader *FirstNode = SizeClassFreeNodeList) {
unsigned FirstNodeSize = FirstNode->Size;
- if (FirstNodeSize > 2*NumBytes+sizeof(NodeHeader)) {
- // Put the remainder back on the list...
- FreedNodeHeader *NextNodes =
- (FreedNodeHeader*)((char*)FirstNode + sizeof(NodeHeader) + NumBytes);
- NextNodes->Size = FirstNodeSize-NumBytes-sizeof(NodeHeader);
- NextNodes->NormalHeader.Next = FirstNode->NormalHeader.Next;
- Pool->FreeNodeList = NextNodes;
- FirstNode->NormalHeader.ObjectSize = NumBytes;
- DEBUG(printf("alloc Pool:0x%X Bytes:%d -> 0x%X\n", Pool, NumBytes,
- &FirstNode->NormalHeader+1));
- return &FirstNode->NormalHeader+1;
- } else if (FirstNodeSize > NumBytes) {
- Pool->FreeNodeList = FirstNode->NormalHeader.Next; // Unlink
+ if (FirstNodeSize > NumBytes) {
+ if (FirstNodeSize >= 2*NumBytes+sizeof(NodeHeader)) {
+ // Put the remainder back on the list...
+ FreedNodeHeader *NextNodes =
+ (FreedNodeHeader*)((char*)FirstNode + sizeof(NodeHeader) + NumBytes);
+
+ // Remove from list
+ Pool->FreeNodeLists[SizeClass] = FirstNode->NormalHeader.Next;
+
+ NextNodes->Size = FirstNodeSize-NumBytes-sizeof(NodeHeader);
+ AddNodeToFreeList(Pool, NextNodes);
+
+ FirstNode->NormalHeader.ObjectSize = NumBytes;
+ DEBUG(printf("alloc Pool:0x%X Bytes:%d -> 0x%X\n", Pool, NumBytes,
+ &FirstNode->NormalHeader+1));
+ return &FirstNode->NormalHeader+1;
+ }
+
+ Pool->FreeNodeLists[SizeClass] = FirstNode->NormalHeader.Next; // Unlink
FirstNode->NormalHeader.ObjectSize = FirstNodeSize;
DEBUG(printf("alloc Pool:0x%X Bytes:%d -> 0x%X\n", Pool, NumBytes,
&FirstNode->NormalHeader+1));
@@ -145,7 +180,7 @@
// that is big enough.
if (NumBytes <= PageSize-sizeof(PoolSlab)-sizeof(NodeHeader)) {
do {
- FreedNodeHeader **FN = &Pool->FreeNodeList;
+ FreedNodeHeader **FN = &Pool->FreeNodeLists[SizeClass];
FreedNodeHeader *FNN = *FN;
// Search the list for the first-fit
@@ -157,12 +192,14 @@
// the free list, otherwise, slice a little bit off and adjust the free
// list.
if (FNN->Size > 2*NumBytes+sizeof(NodeHeader)) {
- // Put the remainder back on the list...
+ *FN = FNN->NormalHeader.Next; // Unlink
+
+ // Put the remainder back on the list...
FreedNodeHeader *NextNodes =
(FreedNodeHeader*)((char*)FNN + sizeof(NodeHeader) + NumBytes);
NextNodes->Size = FNN->Size-NumBytes-sizeof(NodeHeader);
- NextNodes->NormalHeader.Next = FNN->NormalHeader.Next;
- *FN = NextNodes;
+ AddNodeToFreeList(Pool, NextNodes);
+
FNN->NormalHeader.ObjectSize = NumBytes;
DEBUG(printf("alloc Pool:0x%X Bytes:%d -> 0x%X\n", Pool, NumBytes,
&FNN->NormalHeader+1));
@@ -176,9 +213,13 @@
}
}
- // Oops, we didn't find anything on the free list big enough! Allocate
- // another slab and try again.
- PoolSlab::create(Pool);
+ if (SizeClass < LargeFreeList) {
+ ++SizeClass;
+ } else {
+ // Oops, we didn't find anything on the free list big enough! Allocate
+ // another slab and try again.
+ PoolSlab::create(Pool, NumBytes);
+ }
} while (1);
}
@@ -204,40 +245,41 @@
if (Pool == 0) { free(Node); return; }
if (Node == 0) return;
- DEBUG(printf("free 0x%X <- 0x%X\n", Pool, Node));
-
// Check to see how many elements were allocated to this node...
FreedNodeHeader *FNH = (FreedNodeHeader*)((char*)Node-sizeof(NodeHeader));
unsigned Size = FNH->NormalHeader.ObjectSize;
+
+ DEBUG(printf("free Pool:0x%X <- 0x%X Size:%d\n", Pool, Node, Size));
+
if (Size == ~0U) goto LargeArrayCase;
- // If there are already nodes on the freelist, see if this blocks should be
+ // If there are already nodes on the freelist, see if these blocks can be
// coallesced into one of the early blocks on the front of the list. This is
// a simple check that prevents many horrible forms of fragmentation.
//
- if (FreedNodeHeader *CurFrontNode = Pool->FreeNodeList) {
- if ((char*)FNH + sizeof(NodeHeader) + Size == (char*)CurFrontNode) {
- // This node immediately preceeds the node on the front of the
- // free-list. Remove the current front of the free list, replacing it
- // with the current block.
- FNH->Size = Size + CurFrontNode->Size+sizeof(NodeHeader);
- FNH->NormalHeader.Next = CurFrontNode->NormalHeader.Next;
- Pool->FreeNodeList = FNH;
- return;
+ for (unsigned SizeClass = 0; SizeClass <= LargeFreeList; ++SizeClass)
+ if (FreedNodeHeader *CurFrontNode = Pool->FreeNodeLists[SizeClass]) {
+ if ((char*)FNH + sizeof(NodeHeader) + Size == (char*)CurFrontNode) {
+ // This node immediately preceeds the node on the front of the
+ // free-list. Remove the current front of the free list, replacing it
+ // with the current block.
+ FNH->Size = Size + CurFrontNode->Size+sizeof(NodeHeader);
+ FNH->NormalHeader.Next = CurFrontNode->NormalHeader.Next;
+ Pool->FreeNodeLists[SizeClass] = FNH;
+ return;
+ }
+
+ if ((char*)CurFrontNode + sizeof(NodeHeader) + CurFrontNode->Size ==
+ (char*)FNH) {
+ // This node immediately follows the node on the front of the free-list.
+ // No list manipulation is required.
+ CurFrontNode->Size += Size+sizeof(NodeHeader);
+ return;
+ }
}
- if ((char*)CurFrontNode + sizeof(NodeHeader) + CurFrontNode->Size ==
- (char*)FNH) {
- // This node immediately follows the node on the front of the free-list.
- // No list manipulation is required.
- CurFrontNode->Size += Size+sizeof(NodeHeader);
- return;
- }
- }
-
FNH->Size = Size;
- FNH->NormalHeader.Next = Pool->FreeNodeList;
- Pool->FreeNodeList = FNH;
+ AddNodeToFreeList(Pool, FNH);
return;
LargeArrayCase:
Index: poolalloc/runtime/FL2Allocator/PoolAllocator.h
diff -u poolalloc/runtime/FL2Allocator/PoolAllocator.h:1.2 poolalloc/runtime/FL2Allocator/PoolAllocator.h:1.3
--- poolalloc/runtime/FL2Allocator/PoolAllocator.h:1.2 Thu Mar 4 22:39:09 2004
+++ poolalloc/runtime/FL2Allocator/PoolAllocator.h Fri Mar 5 00:44:55 2004
@@ -51,23 +51,44 @@
};
+// FreeList*Size - These are size classes for each of the freelists in a pool.
+// An object in a particular free list is guaranteed to be <= this size.
+enum {
+ FreeListZeroSize = 16,
+ FreeListOneSize = 64,
+ FreeListTwoSize = 256,
+
+ // There are four free lists.
+ LargeFreeList = 3
+};
+
struct PoolTy {
// Lists - the list of slabs in this pool.
PoolSlab *Slabs;
+ // The free node lists for objects of various sizes.
+ FreedNodeHeader *FreeNodeLists[4];
+
+ // NumObjects - the number of poolallocs for this pool.
+ unsigned NumObjects;
+
+ // BytesAllocated - The total number of bytes ever allocated from this pool.
+ // Together with NumObjects, allows us to calculate average object size.
+ unsigned BytesAllocated;
+
// LargeArrays - A doubly linked list of large array chunks, dynamically
// allocated with malloc.
LargeArrayHeader *LargeArrays;
- // The list of free'd nodes.
- FreedNodeHeader *FreeNodeList;
-
// The size to allocate for the next slab.
unsigned AllocSize;
+
+ // The declared size of the pool, just kept for the record.
+ unsigned DeclaredSize;
};
extern "C" {
- void poolinit(PoolTy *Pool);
+ void poolinit(PoolTy *Pool, unsigned DeclaredSize);
void poolmakeunfreeable(PoolTy *Pool);
void pooldestroy(PoolTy *Pool);
void *poolalloc(PoolTy *Pool, unsigned NumBytes);
More information about the llvm-commits
mailing list