[llvm-commits] CVS: poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp PoolAllocator.h

Chris Lattner lattner at cs.uiuc.edu
Wed Nov 10 17:44:04 PST 2004



Changes in directory poolalloc/runtime/FL2Allocator:

FreeListAllocator.cpp updated: 1.27 -> 1.28
PoolAllocator.h updated: 1.14 -> 1.15

---
Log message:

Instead of maintaining 4 freelists (for object sizes 8,12,16 and other),
only maintain 2 freelists: one for the inferred object size and one for 
'other'.  This dramatically simplifies the poolalloc allocation path and
makes use of the information that PA can infer.



---
Diffs of the changes:  (+123 -115)

Index: poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp
diff -u poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp:1.27 poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp:1.28
--- poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp:1.27	Wed Nov 10 18:32:45 2004
+++ poolalloc/runtime/FL2Allocator/FreeListAllocator.cpp	Wed Nov 10 19:43:54 2004
@@ -140,18 +140,16 @@
 //  PoolSlab implementation
 //===----------------------------------------------------------------------===//
 
-static inline unsigned getSizeClass(unsigned NumBytes) {
-  if (NumBytes <= FreeListOneSize)
-    return NumBytes > FreeListZeroSize;
+static void AddNodeToFreeList(PoolTy *Pool, FreedNodeHeader *FreeNode) {
+  FreedNodeHeader **FreeList;
+  if (FreeNode->Header.Size == Pool->DeclaredSize)
+    FreeList = &Pool->ObjFreeList;
   else
-    return 2 + (NumBytes > FreeListTwoSize);
-}
+    FreeList = &Pool->OtherFreeList;
 
-static void AddNodeToFreeList(PoolTy *Pool, FreedNodeHeader *FreeNode) {
-  unsigned SizeClass = getSizeClass(FreeNode->Header.Size);
-  FreeNode->PrevP = &Pool->FreeNodeLists[SizeClass];
-  FreeNode->Next = Pool->FreeNodeLists[SizeClass];
-  Pool->FreeNodeLists[SizeClass] = FreeNode;
+  FreeNode->PrevP = FreeList;
+  FreeNode->Next = *FreeList;
+  *FreeList = FreeNode;
   if (FreeNode->Next)
     FreeNode->Next->PrevP = &FreeNode->Next;
 }
@@ -181,6 +179,9 @@
 
 // create - Create a new (empty) slab and add it to the end of the Pools list.
 void PoolSlab::create(PoolTy *Pool, unsigned SizeHint) {
+  if (Pool->DeclaredSize == 0)
+    Pool->DeclaredSize = SizeHint;
+
   unsigned Size = Pool->AllocSize;
   Pool->AllocSize <<= 1;
   Size = (Size+SizeHint-1) / SizeHint * SizeHint;
@@ -219,9 +220,11 @@
   Pool->AllocSize <<= 1;
   PoolSlab *PS = (PoolSlab*)malloc(Size+sizeof(PoolSlab));
   char *PoolBody = (char*)(PS+1);
+  if (sizeof(PoolSlab) == 4)
+    PoolBody += 4;            // No reason to start out unaligned.
 
   // Update the end pointer.
-  Pool->FreeNodeLists[1] = (FreedNodeHeader*)(PoolBody+Size);
+  Pool->OtherFreeList = (FreedNodeHeader*)((char*)(PS+1)+Size);
 
   // Add the slab to the list...
   PS->Next = Pool->Slabs;
@@ -247,8 +250,8 @@
   Pool->AllocSize = INITIAL_SLAB_SIZE;
   Pool->Alignment = ObjAlignment;
   Pool->LargeArrays = 0;
-  Pool->FreeNodeLists[0] = 0;   // This is our bump pointer.
-  Pool->FreeNodeLists[1] = 0;   // This is our end pointer.
+  Pool->ObjFreeList = 0;     // This is our bump pointer.
+  Pool->OtherFreeList = 0;   // This is our end pointer.
 
   DO_IF_TRACE(fprintf(stderr, "[%d] poolinit_bp(0x%X, %d)\n",
                       addPoolNumber(Pool), Pool, ObjAlignment));
@@ -273,8 +276,8 @@
   unsigned Alignment;
   char *BumpPtr, *EndPtr;
   Alignment = Pool->Alignment-1;
-  BumpPtr = (char*)Pool->FreeNodeLists[0]; // Get our bump pointer.
-  EndPtr  = (char*)Pool->FreeNodeLists[1]; // Get our end pointer.
+  BumpPtr = (char*)Pool->ObjFreeList; // Get our bump pointer.
+  EndPtr  = (char*)Pool->OtherFreeList; // Get our end pointer.
 
 TryAgain:
   // Align the bump pointer to the required boundary.
@@ -283,13 +286,13 @@
   if (BumpPtr + NumBytes < EndPtr) {
     void *Result = BumpPtr;
     // Update bump ptr.
-    Pool->FreeNodeLists[0] = (FreedNodeHeader*)(BumpPtr+NumBytes);
+    Pool->ObjFreeList = (FreedNodeHeader*)(BumpPtr+NumBytes);
     DO_IF_TRACE(fprintf(stderr, "0x%X\n", Result));
     return Result;
   }
   
   BumpPtr = (char*)PoolSlab::create_for_bp(Pool);
-  EndPtr  = (char*)Pool->FreeNodeLists[1]; // Get our updated end pointer.  
+  EndPtr  = (char*)Pool->OtherFreeList; // Get our updated end pointer.  
   goto TryAgain;
 
 LargeObject:
@@ -341,10 +344,17 @@
   assert(Pool && "Null pool pointer passed into poolinit!\n");
   memset(Pool, 0, sizeof(PoolTy));
   Pool->AllocSize = INITIAL_SLAB_SIZE;
-  Pool->DeclaredSize = DeclaredSize;
+
   if (ObjAlignment < 4) ObjAlignment = __alignof(double);
   Pool->Alignment = ObjAlignment;
 
+  // Round the declared size up to an alignment boundary-header size, just like
+  // we have to do for objects.
+  DeclaredSize = DeclaredSize+sizeof(FreedNodeHeader)+(ObjAlignment-1);
+  DeclaredSize = (DeclaredSize & ~(ObjAlignment-1))-sizeof(FreedNodeHeader);
+
+  Pool->DeclaredSize = DeclaredSize;
+
   DO_IF_TRACE(fprintf(stderr, "[%d] poolinit(0x%X, %d, %d)\n",
                       addPoolNumber(Pool), Pool, DeclaredSize, ObjAlignment));
   DO_IF_PNP(++PoolsInited);  // Track # pools initialized
@@ -403,81 +413,81 @@
   DO_IF_PNP(++Pool->NumObjects);
   DO_IF_PNP(Pool->BytesAllocated += NumBytes);
 
+  // Fast path - allocate objects off the object list.
+  if (NumBytes == Pool->DeclaredSize && Pool->ObjFreeList != 0) {
+    FreedNodeHeader *Node = Pool->ObjFreeList;
+    UnlinkFreeNode(Node);
+    assert(NumBytes == Node->Header.Size);
+
+    Node->Header.Size = NumBytes|1;   // Mark as allocated
+    DO_IF_TRACE(fprintf(stderr, "0x%X\n", &Node->Header+1));
+    return &Node->Header+1;
+  }
+    
   if (NumBytes >= LARGE_SLAB_SIZE-sizeof(PoolSlab)-sizeof(NodeHeader))
     goto LargeObject;
 
-  // Figure out which size class to start scanning from.
-  unsigned SizeClass;
-  SizeClass = getSizeClass(NumBytes);
-
-  // Scan for a class that has entries!
-  while (SizeClass < 3 && Pool->FreeNodeLists[SizeClass] == 0)
-    ++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->FreeNodeLists[SizeClass]) {
-    unsigned FirstNodeSize = FirstNode->Header.Size;
-    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
-        UnlinkFreeNode(FirstNode);
-
-        NextNodes->Header.Size = FirstNodeSize-NumBytes-sizeof(NodeHeader);
-        AddNodeToFreeList(Pool, NextNodes);
-
-      } else {
-        UnlinkFreeNode(FirstNode);
-        NumBytes = FirstNodeSize;
-      }
-      FirstNode->Header.Size = NumBytes|1;   // Mark as allocated
-      DO_IF_TRACE(fprintf(stderr, "0x%X\n", &FirstNode->Header+1));
-      return &FirstNode->Header+1;
-    }
-  }
-
-  // Perform a search of the free list, taking the front of the first free chunk
-  // that is big enough.
   do {
-    FreedNodeHeader **FN = &Pool->FreeNodeLists[SizeClass];
-    FreedNodeHeader *FNN = *FN;
+    FreedNodeHeader *FirstNode = Pool->OtherFreeList;
+    if (FirstNode) {
+      unsigned FirstNodeSize = FirstNode->Header.Size;
+      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
+          UnlinkFreeNode(FirstNode);
+          
+          NextNodes->Header.Size = FirstNodeSize-NumBytes-sizeof(NodeHeader);
+          AddNodeToFreeList(Pool, NextNodes);
+          
+        } else {
+          UnlinkFreeNode(FirstNode);
+          NumBytes = FirstNodeSize;
+        }
+        FirstNode->Header.Size = NumBytes|1;   // Mark as allocated
+        DO_IF_TRACE(fprintf(stderr, "0x%X\n", &FirstNode->Header+1));
+        return &FirstNode->Header+1;
+      }
 
-    // Search the list for the first-fit
-    while (FNN && FNN->Header.Size < NumBytes)
-      FN = &FNN->Next, FNN = *FN;
-
-    if (FNN) {
-      // We found a slab big enough.  If it's a perfect fit, just unlink from
-      // the free list, otherwise, slice a little bit off and adjust the free
-      // list.
-      if (FNN->Header.Size > 2*NumBytes+sizeof(NodeHeader)) {
-        UnlinkFreeNode(FNN);
-
-        // Put the remainder back on the list...
-        FreedNodeHeader *NextNodes =
-          (FreedNodeHeader*)((char*)FNN + sizeof(NodeHeader) + NumBytes);
-        NextNodes->Header.Size = FNN->Header.Size-NumBytes-sizeof(NodeHeader);
-        AddNodeToFreeList(Pool, NextNodes);
-      } else {
-        UnlinkFreeNode(FNN);
-        NumBytes = FNN->Header.Size;
+      // Perform a search of the free list, taking the front of the first free
+      // chunk that is big enough.
+      FreedNodeHeader **FN = &Pool->OtherFreeList;
+      FreedNodeHeader *FNN = FirstNode;
+      
+      // Search the list for the first-fit.
+      while (FNN && FNN->Header.Size < NumBytes)
+        FN = &FNN->Next, FNN = *FN;
+      
+      if (FNN) {
+        // We found a slab big enough.  If it's a perfect fit, just unlink
+        // from the free list, otherwise, slice a little bit off and adjust
+        // the free list.
+        if (FNN->Header.Size > 2*NumBytes+sizeof(NodeHeader)) {
+          UnlinkFreeNode(FNN);
+          
+          // Put the remainder back on the list...
+          FreedNodeHeader *NextNodes =
+            (FreedNodeHeader*)((char*)FNN + sizeof(NodeHeader) + NumBytes);
+          NextNodes->Header.Size = FNN->Header.Size-NumBytes-sizeof(NodeHeader);
+          AddNodeToFreeList(Pool, NextNodes);
+        } else {
+          UnlinkFreeNode(FNN);
+          NumBytes = FNN->Header.Size;
+        }
+        FNN->Header.Size = NumBytes|1;   // Mark as allocated
+        DO_IF_TRACE(fprintf(stderr, "0x%X\n", &FNN->Header+1));
+        return &FNN->Header+1;
       }
-      FNN->Header.Size = NumBytes|1;   // Mark as allocated
-      DO_IF_TRACE(fprintf(stderr, "0x%X\n", &FNN->Header+1));
-      return &FNN->Header+1;
     }
 
-    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);
-    }
+    // Oops, we didn't find anything on the free list big enough!  Allocate
+    // another slab and try again.
+    PoolSlab::create(Pool, NumBytes);
   } while (1);
 
 LargeObject:
@@ -528,15 +538,23 @@
   // a simple check that prevents many horrible forms of fragmentation,
   // particularly when freeing objects in allocation order.
   //
-  for (unsigned SizeClass = 0; SizeClass <= LargeFreeList; ++SizeClass)
-    if (FreedNodeHeader *CurFrontNode = Pool->FreeNodeLists[SizeClass])
-      if ((char*)CurFrontNode + sizeof(NodeHeader) + CurFrontNode->Header.Size==
-          (char*)FNH) {
-        // This node immediately follows the node on the front of the free-list.
-        // No list manipulation is required.
-        CurFrontNode->Header.Size += Size+sizeof(NodeHeader);
-        return;
-      }
+  if (FreedNodeHeader *ObjFNH = Pool->ObjFreeList)
+    if ((char*)ObjFNH + sizeof(NodeHeader) + ObjFNH->Header.Size == (char*)FNH){
+      // Merge this with a node that is already on the object size free list.
+      // Because the object is growing, we will never be able to find it if we
+      // leave it on the object freelist.
+      UnlinkFreeNode(ObjFNH);
+      ObjFNH->Header.Size += Size+sizeof(NodeHeader);
+      AddNodeToFreeList(Pool, ObjFNH);
+      return;
+    }
+
+  if (FreedNodeHeader *OFNH = Pool->OtherFreeList)
+    if ((char*)OFNH + sizeof(NodeHeader) + OFNH->Header.Size == (char*)FNH) {
+      // Merge this with a node that is already on the object size free list.
+      OFNH->Header.Size += Size+sizeof(NodeHeader);
+      return;
+    }
 
   FNH->Header.Size = Size;
   AddNodeToFreeList(Pool, FNH);


Index: poolalloc/runtime/FL2Allocator/PoolAllocator.h
diff -u poolalloc/runtime/FL2Allocator/PoolAllocator.h:1.14 poolalloc/runtime/FL2Allocator/PoolAllocator.h:1.15
--- poolalloc/runtime/FL2Allocator/PoolAllocator.h:1.14	Wed Nov 10 16:01:58 2004
+++ poolalloc/runtime/FL2Allocator/PoolAllocator.h	Wed Nov 10 19:43:54 2004
@@ -68,33 +68,16 @@
 };
 
 
-// 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 = 8,
-  FreeListOneSize  = 12,
-  FreeListTwoSize  = 16,
-
-  // 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];
+  FreedNodeHeader *ObjFreeList;
+  FreedNodeHeader *OtherFreeList;
 
   // Alignment - The required alignment of allocations the pool in bytes.
   unsigned Alignment;
 
-  // 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;
+  // The declared size of the pool, just kept for the record.
+  unsigned DeclaredSize;
 
   // LargeArrays - A doubly linked list of large array chunks, dynamically
   // allocated with malloc.
@@ -103,8 +86,15 @@
   // The size to allocate for the next slab.
   unsigned AllocSize;
 
-  // The declared size of the pool, just kept for the record.
-  unsigned DeclaredSize;
+  // Lists - the list of slabs in this pool.
+  PoolSlab *Slabs;
+
+  // 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;
 };
 
 extern "C" {





More information about the llvm-commits mailing list