[compiler-rt] 7ce67d3 - [scudo][tests] Store the allocator instance in a global rather than posix_memalign it

Leonard Chan via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 31 15:27:33 PDT 2023


Author: Leonard Chan
Date: 2023-08-31T22:27:14Z
New Revision: 7ce67d33107fd86b7fac985a593e14298944a3a8

URL: https://github.com/llvm/llvm-project/commit/7ce67d33107fd86b7fac985a593e14298944a3a8
DIFF: https://github.com/llvm/llvm-project/commit/7ce67d33107fd86b7fac985a593e14298944a3a8.diff

LOG: [scudo][tests] Store the allocator instance in a global rather than posix_memalign it

The combined scudo allocator object is over 4MB in size which gets created via
the posix_memalign on every test run. If the tests are sanitized with asan,
then the asan allocator will need to mmap this large object every single time a
test is run. Depending on where this is mapped, we might not be able to find a
large enough contiguous space for scudo's primary allocator to reserve an arena.
Such a case is more likely to occur on 39-bit vma for RISCV where the arena size
is roughly a quarter of the whole address space and fragmentation can be a big issue.

This helps reduce fragmentation by instead placing the allocator instance in a
global storage rather than doing an anonymous mmap.

Differential Revision: https://reviews.llvm.org/D158767

Added: 
    

Modified: 
    compiler-rt/lib/scudo/standalone/tests/combined_test.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
index 6d381eab645115..fc118fcadc6b6c 100644
--- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
@@ -78,14 +78,72 @@ template <typename Config> struct TestAllocator : scudo::Allocator<Config> {
   }
   ~TestAllocator() { this->unmapTestOnly(); }
 
-  void *operator new(size_t size) {
+  void *operator new(size_t size);
+  void operator delete(void *ptr);
+};
+
+constexpr size_t kMaxAlign = std::max({
+  alignof(scudo::Allocator<scudo::DefaultConfig>),
+#if SCUDO_CAN_USE_PRIMARY64
+      alignof(scudo::Allocator<scudo::FuchsiaConfig>),
+#endif
+      alignof(scudo::Allocator<scudo::AndroidSvelteConfig>),
+      alignof(scudo::Allocator<scudo::AndroidConfig>)
+});
+
+#if SCUDO_RISCV64
+// The allocator is over 4MB large. Rather than creating an instance of this on
+// the heap, keep it in a global storage to reduce fragmentation from having to
+// mmap this at the start of every test.
+struct TestAllocatorStorage {
+  static constexpr size_t kMaxSize = std::max({
+    sizeof(scudo::Allocator<scudo::DefaultConfig>),
+#if SCUDO_CAN_USE_PRIMARY64
+        sizeof(scudo::Allocator<scudo::FuchsiaConfig>),
+#endif
+        sizeof(scudo::Allocator<scudo::AndroidSvelteConfig>),
+        sizeof(scudo::Allocator<scudo::AndroidConfig>)
+  });
+
+  // To alleviate some problem, let's skip the thread safety analysis here.
+  static void *get(size_t size) NO_THREAD_SAFETY_ANALYSIS {
+    assert(size <= kMaxSize &&
+           "Allocation size doesn't fit in the allocator storage");
+    M.lock();
+    return AllocatorStorage;
+  }
+
+  static void release(void *ptr) NO_THREAD_SAFETY_ANALYSIS {
+    M.assertHeld();
+    M.unlock();
+    ASSERT_EQ(ptr, AllocatorStorage);
+  }
+
+  static scudo::HybridMutex M;
+  static uint8_t AllocatorStorage[kMaxSize];
+};
+scudo::HybridMutex TestAllocatorStorage::M;
+alignas(kMaxAlign) uint8_t TestAllocatorStorage::AllocatorStorage[kMaxSize];
+#else
+struct TestAllocatorStorage {
+  static void *get(size_t size) NO_THREAD_SAFETY_ANALYSIS {
     void *p = nullptr;
-    EXPECT_EQ(0, posix_memalign(&p, alignof(TestAllocator), size));
+    EXPECT_EQ(0, posix_memalign(&p, kMaxAlign, size));
     return p;
   }
-
-  void operator delete(void *ptr) { free(ptr); }
+  static void release(void *ptr) NO_THREAD_SAFETY_ANALYSIS { free(ptr); }
 };
+#endif
+
+template <typename Config>
+void *TestAllocator<Config>::operator new(size_t size) {
+  return TestAllocatorStorage::get(size);
+}
+
+template <typename Config>
+void TestAllocator<Config>::operator delete(void *ptr) {
+  TestAllocatorStorage::release(ptr);
+}
 
 template <class TypeParam> struct ScudoCombinedTest : public Test {
   ScudoCombinedTest() {


        


More information about the llvm-commits mailing list