[llvm-commits] CVS: poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp

Chris Lattner lattner at cs.uiuc.edu
Sun Oct 26 19:52:01 PST 2003


Changes in directory poolalloc/runtime/PoolAllocator:

PoolAllocatorChained.cpp updated: 1.16 -> 1.17

---
Log message:

Change the poolallocator to keep TWO lists of slabs: one which has partially 
allocated elements in it, and one which has completely full elements. This 
allows the "always allocating" case to take constant time, instead of the
horrible linear-time-for-each-allocation we were seeing.  This speeds up
treeadd on one testcase from taking 2.546 seconds to taking 1.474s, but of
arbitrary speedups can be aquired by increasing the problem size.


---
Diffs of the changes:  (+104 -42)

Index: poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp
diff -u poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp:1.16 poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp:1.17
--- poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp:1.16	Sun Oct 26 17:27:31 2003
+++ poolalloc/runtime/PoolAllocator/PoolAllocatorChained.cpp	Sun Oct 26 19:51:22 2003
@@ -1,6 +1,6 @@
 //===- PoolAllocatorChained.cpp - Implementation of poolallocator runtime -===//
 // 
-//                     The LLVM Compiler Infrastructure
+//                       The LLVM Compiler Infrastructure
 //
 // This file was developed by the LLVM research group and is distributed under
 // the University of Illinois Open Source License. See LICENSE.TXT for details.
@@ -10,6 +10,11 @@
 // This file is one possible implementation of the LLVM pool allocator runtime
 // library.
 //
+// This uses the 'Ptr1' field to maintain a linked list of slabs that are either
+// empty or are partially allocated from.  The 'Ptr2' field of the PoolTy is
+// used to track a linked list of slabs which are full, ie, all elements have
+// been allocated from them.
+//
 //===----------------------------------------------------------------------===//
 
 #include "PoolAllocator.h"
@@ -98,6 +103,10 @@
   // not.
   bool isEmpty() const { return UsedEnd == 0; }
 
+  // isFull - This is a quick check to see if the slab is completely allocated.
+  //
+  bool isFull() const { return isSingleArray || FirstUnused == NodesPerSlab; }
+
   // allocateSingle - Allocate a single element from this pool, returning -1 if
   // there is no space.
   int allocateSingle();
@@ -145,9 +154,9 @@
   PS->isSingleArray = 1;  // Not a single array!
   PS->markNodeAllocated(0);
 
-  // Add the slab to the list...
-  PS->Next = (PoolSlab*)Pool->Ptr1;
-  Pool->Ptr1 = PS;
+  // Add the slab to the list of completely allocated slabs...
+  PS->Next = (PoolSlab*)Pool->Ptr2;
+  Pool->Ptr2 = PS;
   return &PS->Data[0];
 }
 
@@ -343,7 +352,7 @@
 
   // We must alway return unique pointers, even if they asked for 0 bytes
   Pool->NodeSize = NodeSize ? NodeSize : 1;
-  Pool->Ptr1 = 0;
+  Pool->Ptr1 = Pool->Ptr2 = 0;
   Pool->FreeablePool = 1;
 }
 
@@ -357,12 +366,21 @@
 void pooldestroy(PoolTy *Pool) {
   assert(Pool && "Null pool pointer passed in to pooldestroy!\n");
 
+  // Free any partially allocated slabs
   PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
   while (PS) {
     PoolSlab *Next = PS->Next;
     PS->destroy();
     PS = Next;
   }
+
+  // Free the completely allocated slabs
+  PS = (PoolSlab*)Pool->Ptr2;
+  while (PS) {
+    PoolSlab *Next = PS->Next;
+    PS->destroy();
+    PS = Next;
+  }
 }
 
 void *poolalloc(PoolTy *Pool) {
@@ -370,20 +388,22 @@
 
   unsigned NodeSize = Pool->NodeSize;
   PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
-
-  // Fastpath for allocation in the common case.
-  if (PS) {
-    int Element = PS->allocateSingle();
-    if (Element != -1)
-      return PS->getElementAddress(Element, NodeSize);
-    PS = PS->Next;
-  }
+  PoolSlab **PPS = (PoolSlab**)&Pool->Ptr1;
 
   // Loop through all of the slabs looking for one with an opening
-  for (; PS; PS = PS->Next) {
+  for (; PS; PPS = &PS->Next, PS = PS->Next) {
     int Element = PS->allocateSingle();
-    if (Element != -1)
+    if (Element != -1) {
+      // We allocated an element.  Check to see if this slab has been completely
+      // filled up.  If so, move it to the Ptr2 list.
+      if (PS->isFull()) {
+        *PPS = PS->Next;                    // Unlink it from the current list
+        PS->Next = (PoolSlab*)Pool->Ptr2;   // Link it into the filled list
+        Pool->Ptr2 = PS;
+      }
+
       return PS->getElementAddress(Element, NodeSize);
+    }
   }
 
   // Otherwise we must allocate a new slab and add it to the list
@@ -393,19 +413,82 @@
   return New->getElementAddress(0, 0);
 }
 
+void *poolallocarray(PoolTy* Pool, unsigned Size) {
+  assert(Pool && "Null pool pointer passed into poolallocarray!\n");
+
+  if (Size > PoolSlab::NodesPerSlab)
+    return PoolSlab::createSingleArray(Pool, Size);    
+
+  PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
+  PoolSlab **PPS = (PoolSlab**)&Pool->Ptr1;
+
+  // Loop through all of the slabs looking for one with an opening
+  for (; PS; PPS = &PS->Next, PS = PS->Next) {
+    int Element = PS->allocateMultiple(Size);
+    if (Element != -1) {
+      // We allocated an element.  Check to see if this slab has been completely
+      // filled up.  If so, move it to the Ptr2 list.
+      if (PS->isFull()) {
+        *PPS = PS->Next;                    // Unlink it from the current list
+        PS->Next = (PoolSlab*)Pool->Ptr2;   // Link it into the filled list
+        Pool->Ptr2 = PS;
+      }
+      return PS->getElementAddress(Element, Pool->NodeSize);
+    }
+    PS = PS->Next;
+  }
+  
+  PoolSlab *New = PoolSlab::create(Pool);
+  int Idx = New->allocateMultiple(Size);
+  assert(Idx == 0 && "New allocation didn't return zero'th node?");
+  return New->getElementAddress(0, 0);
+}
+
 void poolfree(PoolTy *Pool, void *Node) {
   assert(Pool && "Null pool pointer passed in to poolfree!\n");
   unsigned NodeSize = Pool->NodeSize;
 
   PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
-  PoolSlab **PPS = (PoolSlab**)&Pool->Ptr1;
+  PoolSlab **PPS;
 
-  // Search for the slab that contains this node...
-  int Idx = PS->containsElement(Node, NodeSize);
-  for (; Idx == -1; PPS = &PS->Next, PS = PS->Next) {
-    assert(PS && "poolfree: node being free'd not found in allocation "
-           " pool specified!\n");
+  // Search the partially allocated slab list for the slab that contains this
+  // node.
+  int Idx = -1;
+  if (PS) {               // Pool->Ptr1 could be null if Ptr2 isn't
+    PPS = (PoolSlab**)&Pool->Ptr1;
+    PS->containsElement(Node, NodeSize);
+    for (; Idx == -1 && PS; PPS = &PS->Next, PS = PS->Next)
+      Idx = PS->containsElement(Node, NodeSize);
+  }
+
+  // If the partially allocated slab list doesn't contain it, maybe the
+  // completely allocated list does.
+  if (PS == 0) {
+    PS = (PoolSlab*)Pool->Ptr2;
+    PPS = (PoolSlab**)&Pool->Ptr2;
+    
     Idx = PS->containsElement(Node, NodeSize);
+    for (; Idx == -1; PPS = &PS->Next, PS = PS->Next) {
+      assert(PS && "poolfree: node being free'd not found in allocation "
+             " pool specified!\n");
+      Idx = PS->containsElement(Node, NodeSize);
+    }
+
+    // Now that we found the node, we are about to free an element from it.
+    // This will make the slab no longer completely full, so we must move it to
+    // the other list!
+    *PPS = PS->Next;      // Remove it from the Ptr2 list.
+
+    PoolSlab **InsertPosPtr = (PoolSlab**)&Pool->Ptr1;
+
+    // If the partially full list has an empty node sitting at the front of the
+    // list, insert right after it.
+    if ((*InsertPosPtr)->isEmpty())
+      InsertPosPtr = &(*InsertPosPtr)->Next;
+    
+    // Insert it now in the Ptr1 list.
+    PS->Next = *InsertPosPtr;
+    *InsertPosPtr = PS;
   }
 
   // Free the actual element now!
@@ -450,25 +533,4 @@
     PS->Next = FirstSlab;
     Pool->Ptr1 = PS;
   }
-}
-
-void *poolallocarray(PoolTy* Pool, unsigned Size) {
-  assert(Pool && "Null pool pointer passed into poolallocarray!\n");
-
-  if (Size > PoolSlab::NodesPerSlab)
-    return PoolSlab::createSingleArray(Pool, Size);    
-
-  // Loop through all of the slabs looking for one with an opening
-  PoolSlab *PS = (PoolSlab*)Pool->Ptr1;
-  for (; PS; PS = PS->Next) {
-    int Element = PS->allocateMultiple(Size);
-    if (Element != -1)
-      return PS->getElementAddress(Element, Pool->NodeSize);
-    PS = PS->Next;
-  }
-  
-  PoolSlab *New = PoolSlab::create(Pool);
-  int Idx = New->allocateMultiple(Size);
-  assert(Idx == 0 && "New allocation didn't return zero'th node?");
-  return New->getElementAddress(0, 0);
 }





More information about the llvm-commits mailing list