[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