[llvm] 46e5603 - Reland "[llvm] Add a way to speed up the speed in which BumpPtrAllocator increases slab sizes""

Raphael Isemann via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 3 03:06:40 PST 2020


Author: Raphael Isemann
Date: 2020-02-03T12:06:15+01:00
New Revision: 46e5603c8a08de6c5983ed7eb4f12828bbfcbd78

URL: https://github.com/llvm/llvm-project/commit/46e5603c8a08de6c5983ed7eb4f12828bbfcbd78
DIFF: https://github.com/llvm/llvm-project/commit/46e5603c8a08de6c5983ed7eb4f12828bbfcbd78.diff

LOG: Reland "[llvm] Add a way to speed up the speed in which BumpPtrAllocator increases slab sizes""

Disable the red zone in the unit test allocator to fix the test errors in sanitizer builds.
The red zone changed the amount of allocated bytes which made the test fail as it
checked the number of allocated bytes of the allocator.

Added: 
    

Modified: 
    llvm/include/llvm/Support/Allocator.h
    llvm/unittests/Support/AllocatorTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index cf3a709fa8fe..be09bd635219 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -59,16 +59,22 @@ void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated,
 /// The BumpPtrAllocatorImpl template defaults to using a MallocAllocator
 /// object, which wraps malloc, to allocate memory, but it can be changed to
 /// use a custom allocator.
+///
+/// The GrowthDelay specifies after how many allocated slabs the allocator
+/// increases the size of the slabs.
 template <typename AllocatorT = MallocAllocator, size_t SlabSize = 4096,
-          size_t SizeThreshold = SlabSize>
+          size_t SizeThreshold = SlabSize, size_t GrowthDelay = 128>
 class BumpPtrAllocatorImpl
-    : public AllocatorBase<
-          BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold>> {
+    : public AllocatorBase<BumpPtrAllocatorImpl<AllocatorT, SlabSize,
+                                                SizeThreshold, GrowthDelay>> {
 public:
   static_assert(SizeThreshold <= SlabSize,
                 "The SizeThreshold must be at most the SlabSize to ensure "
                 "that objects larger than a slab go into their own memory "
                 "allocation.");
+  static_assert(GrowthDelay > 0,
+                "GrowthDelay must be at least 1 which already increases the"
+                "slab size after each allocated slab.");
 
   BumpPtrAllocatorImpl() = default;
 
@@ -314,10 +320,11 @@ class BumpPtrAllocatorImpl
 
   static size_t computeSlabSize(unsigned SlabIdx) {
     // Scale the actual allocated slab size based on the number of slabs
-    // allocated. Every 128 slabs allocated, we double the allocated size to
-    // reduce allocation frequency, but saturate at multiplying the slab size by
-    // 2^30.
-    return SlabSize * ((size_t)1 << std::min<size_t>(30, SlabIdx / 128));
+    // allocated. Every GrowthDelay slabs allocated, we double
+    // the allocated size to reduce allocation frequency, but saturate at
+    // multiplying the slab size by 2^30.
+    return SlabSize *
+           ((size_t)1 << std::min<size_t>(30, SlabIdx / GrowthDelay));
   }
 
   /// Allocate a new slab and move the bump pointers over into the new
@@ -421,10 +428,12 @@ template <typename T> class SpecificBumpPtrAllocator {
 
 } // end namespace llvm
 
-template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold>
-void *operator new(size_t Size,
-                   llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize,
-                                              SizeThreshold> &Allocator) {
+template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold,
+          size_t GrowthDelay>
+void *
+operator new(size_t Size,
+             llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold,
+                                        GrowthDelay> &Allocator) {
   struct S {
     char c;
     union {
@@ -438,9 +447,11 @@ void *operator new(size_t Size,
       Size, std::min((size_t)llvm::NextPowerOf2(Size), offsetof(S, x)));
 }
 
-template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold>
-void operator delete(
-    void *, llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold> &) {
+template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold,
+          size_t GrowthDelay>
+void operator delete(void *,
+                     llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize,
+                                                SizeThreshold, GrowthDelay> &) {
 }
 
 #endif // LLVM_SUPPORT_ALLOCATOR_H

diff  --git a/llvm/unittests/Support/AllocatorTest.cpp b/llvm/unittests/Support/AllocatorTest.cpp
index 8a07ddda130e..57c3252fc701 100644
--- a/llvm/unittests/Support/AllocatorTest.cpp
+++ b/llvm/unittests/Support/AllocatorTest.cpp
@@ -134,6 +134,54 @@ TEST(AllocatorTest, TestAlignmentPastSlab) {
   EXPECT_EQ(2U, Alloc.GetNumSlabs());
 }
 
+// Test allocating with a decreased growth delay.
+TEST(AllocatorTest, TestFasterSlabGrowthDelay) {
+  const size_t SlabSize = 4096;
+  // Decrease the growth delay to double the slab size every slab.
+  const size_t GrowthDelay = 1;
+  BumpPtrAllocatorImpl<MallocAllocator, SlabSize, SlabSize, GrowthDelay> Alloc;
+  // Disable the red zone for this test. The additional bytes allocated for the
+  // red zone would change the allocation numbers we check below.
+  Alloc.setRedZoneSize(0);
+
+  Alloc.Allocate(SlabSize, 1);
+  EXPECT_EQ(SlabSize, Alloc.getTotalMemory());
+  // We hit our growth delay with the previous allocation so the next
+  // allocation should get a twice as large slab.
+  Alloc.Allocate(SlabSize, 1);
+  EXPECT_EQ(SlabSize * 3, Alloc.getTotalMemory());
+  Alloc.Allocate(SlabSize, 1);
+  EXPECT_EQ(SlabSize * 3, Alloc.getTotalMemory());
+
+  // Both slabs are full again and hit the growth delay again, so the
+  // next allocation should again get a slab with four times the size of the
+  // original slab size. In total we now should have a memory size of:
+  // 1 + 2 + 4 * SlabSize.
+  Alloc.Allocate(SlabSize, 1);
+  EXPECT_EQ(SlabSize * 7, Alloc.getTotalMemory());
+}
+
+// Test allocating with a increased growth delay.
+TEST(AllocatorTest, TestSlowerSlabGrowthDelay) {
+  const size_t SlabSize = 16;
+  // Increase the growth delay to only double the slab size every 256 slabs.
+  const size_t GrowthDelay = 256;
+  BumpPtrAllocatorImpl<MallocAllocator, SlabSize, SlabSize, GrowthDelay> Alloc;
+  // Disable the red zone for this test. The additional bytes allocated for the
+  // red zone would change the allocation numbers we check below.
+  Alloc.setRedZoneSize(0);
+
+  // Allocate 256 slabs. We should keep getting slabs with the original size
+  // as we haven't hit our growth delay on the last allocation.
+  for (std::size_t i = 0; i < GrowthDelay; ++i)
+    Alloc.Allocate(SlabSize, 1);
+  EXPECT_EQ(SlabSize * GrowthDelay, Alloc.getTotalMemory());
+  // Allocate another slab. This time we should get another slab allocated
+  // that is twice as large as the normal slab size.
+  Alloc.Allocate(SlabSize, 1);
+  EXPECT_EQ(SlabSize * GrowthDelay + SlabSize * 2, Alloc.getTotalMemory());
+}
+
 // Mock slab allocator that returns slabs aligned on 4096 bytes.  There is no
 // easy portable way to do this, so this is kind of a hack.
 class MockSlabAllocator {


        


More information about the llvm-commits mailing list