summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/asan/TestCases/Linux/thread_local_quarantine_pthread_join.cc56
-rw-r--r--test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc38
2 files changed, 76 insertions, 18 deletions
diff --git a/test/asan/TestCases/Linux/thread_local_quarantine_pthread_join.cc b/test/asan/TestCases/Linux/thread_local_quarantine_pthread_join.cc
new file mode 100644
index 000000000..8a5bb25ee
--- /dev/null
+++ b/test/asan/TestCases/Linux/thread_local_quarantine_pthread_join.cc
@@ -0,0 +1,56 @@
+// Test how creating and joining a lot of threads making only a few allocations
+// each affect total quarantine (and overall heap) size.
+
+// RUN: %clangxx_asan %s -o %t
+// RUN: %env_asan_opts=thread_local_quarantine_size_kb=64:quarantine_size_mb=1:allocator_release_to_os_interval_ms=-1 %run %t 2>&1 | \
+// RUN: FileCheck %s --allow-empty --check-prefix=CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sanitizer/allocator_interface.h>
+
+// Thread local quarantine is merged to the global one when thread exits and
+// this scenario (a few allocations per thread) used to generate a huge overhead
+// of practically empty quarantine batches (one per thread).
+static const size_t kHeapSizeIncrementLimit = 2 << 20;
+static const int kNumThreads = 2048;
+// The allocation size is so small because all we want to test is that
+// quarantine block merging process does not leak memory used for quarantine
+// blocks.
+// TODO(alekseyshl): Add more comprehensive test verifying quarantine size
+// directly (requires quarantine stats exposed in allocator stats and API).
+static const int kAllocSize = 1;
+
+void *ThreadFn(void *unused) {
+ char *temp = new char[kAllocSize];
+ memset(temp, -1, kAllocSize);
+ delete [] (temp);
+ return NULL;
+}
+
+int main() {
+ // Warm up all internal structures.
+ pthread_t t;
+ pthread_create(&t, 0, ThreadFn, 0);
+ pthread_join(t, 0);
+
+ size_t heap_size = __sanitizer_get_heap_size();
+ fprintf(stderr, "Heap size: %zd\n", heap_size);
+
+ for (int i = 0; i < kNumThreads; i++) {
+ pthread_t t;
+ pthread_create(&t, 0, ThreadFn, 0);
+ pthread_join(t, 0);
+
+ size_t new_heap_size = __sanitizer_get_heap_size();
+ }
+
+ size_t new_heap_size = __sanitizer_get_heap_size();
+ fprintf(stderr, "New heap size: %zd\n", new_heap_size);
+ if (new_heap_size - heap_size < kHeapSizeIncrementLimit)
+ fprintf(stderr, "Heap growth is within limits\n");
+}
+
+// CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD: Heap growth is within limits
diff --git a/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc b/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc
index 24022a140..46af1a0e0 100644
--- a/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc
+++ b/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc
@@ -1,12 +1,10 @@
// Test thread_local_quarantine_size_kb
// RUN: %clangxx_asan %s -o %t
-// RUN: %env_asan_opts=thread_local_quarantine_size_kb=256:verbosity=1 %run %t 2>&1 | \
-// RUN: FileCheck %s --check-prefix=CHECK-VALUE
-// RUN: %env_asan_opts=thread_local_quarantine_size_kb=64:quarantine_size_mb=64 %run %t 2>&1 | \
+// RUN: %env_asan_opts=thread_local_quarantine_size_kb=64:quarantine_size_mb=64:verbosity=1 %run %t 2>&1 | \
// RUN: FileCheck %s --allow-empty --check-prefix=CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD
// RUN: %env_asan_opts=thread_local_quarantine_size_kb=0:quarantine_size_mb=0 %run %t 2>&1 | \
-// RUN: FileCheck %s --check-prefix=CHECK-QUARANTINE-DISABLED
+// RUN: FileCheck %s --check-prefix=CHECK-QUARANTINE-DISABLED-SMALL-OVERHEAD
// RUN: %env_asan_opts=thread_local_quarantine_size_kb=0:quarantine_size_mb=64 not %run %t 2>&1 | \
// RUN: FileCheck %s --check-prefix=CHECK-FOR-PARAMETER-ERROR
@@ -15,29 +13,33 @@
#include <string.h>
#include <sanitizer/allocator_interface.h>
-// The idea is allocate a lot of small blocks, totaling 5Mb of user memory
-// total, and verify that quarantine does not incur too much memory overhead.
+// The idea is allocate a lot of small blocks, totaling 5Mb of user memory,
+// and verify that quarantine does not incur too much memory overhead.
// There's always an overhead for red zones, shadow memory and such, but
// quarantine accounting should not significantly contribute to that.
+// The zero sized thread local cache is specifically tested since it used to
+// generate a huge overhead of almost empty quarantine batches.
+static const size_t kHeapSizeIncrementLimit = 12 << 20;
static const int kNumAllocs = 20000;
static const int kAllocSize = 256;
-static const size_t kHeapSizeLimit = 12 << 20;
int main() {
- size_t old_heap_size = __sanitizer_get_heap_size();
+ size_t heap_size = __sanitizer_get_heap_size();
+ fprintf(stderr, "Heap size: %zd\n", heap_size);
+
for (int i = 0; i < kNumAllocs; i++) {
- char *g = new char[kAllocSize];
- memset(g, -1, kAllocSize);
- delete [] (g);
+ char *temp = new char[kAllocSize];
+ memset(temp, -1, kAllocSize);
+ delete [] (temp);
}
+
size_t new_heap_size = __sanitizer_get_heap_size();
- fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size,
- old_heap_size);
- if (new_heap_size - old_heap_size > kHeapSizeLimit)
- fprintf(stderr, "Heap size limit exceeded");
+ fprintf(stderr, "New heap size: %zd\n", new_heap_size);
+ if (new_heap_size - heap_size < kHeapSizeIncrementLimit)
+ fprintf(stderr, "Heap growth is within limits\n");
}
-// CHECK-VALUE: thread_local_quarantine_size_kb=256K
-// CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD-NOT: Heap size limit exceeded
-// CHECK-QUARANTINE-DISABLED-NOT: Heap size limit exceeded
+// CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD: thread_local_quarantine_size_kb=64K
+// CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD: Heap growth is within limits
+// CHECK-QUARANTINE-DISABLED-SMALL-OVERHEAD: Heap growth is within limits
// CHECK-FOR-PARAMETER-ERROR: thread_local_quarantine_size_kb can be set to 0 only when quarantine_size_mb is set to 0