summaryrefslogtreecommitdiff
path: root/lib/tsan/benchmarks
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:51:06 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:51:06 +0000
commit8f3cadc28cb2bb9e8f9d69eeaaea1f57f2f7b2ab (patch)
tree05a2b6ec297fe6283d9557c791445d1daf88dcd0 /lib/tsan/benchmarks
parent63714eb5809e39666dec2454c354195e76f916ba (diff)
Notes
Diffstat (limited to 'lib/tsan/benchmarks')
-rw-r--r--lib/tsan/benchmarks/func_entry_exit.cc20
-rw-r--r--lib/tsan/benchmarks/mop.cc80
2 files changed, 100 insertions, 0 deletions
diff --git a/lib/tsan/benchmarks/func_entry_exit.cc b/lib/tsan/benchmarks/func_entry_exit.cc
new file mode 100644
index 0000000000000..5e0ba1d6981ba
--- /dev/null
+++ b/lib/tsan/benchmarks/func_entry_exit.cc
@@ -0,0 +1,20 @@
+// Synthetic benchmark for __tsan_func_entry/exit (spends ~75% there).
+
+void foo(bool x);
+
+int main() {
+ volatile int kRepeat1 = 1 << 30;
+ const int kRepeat = kRepeat1;
+ for (int i = 0; i < kRepeat; i++)
+ foo(false);
+}
+
+__attribute__((noinline)) void bar(volatile bool x) {
+ if (x)
+ foo(x);
+}
+
+__attribute__((noinline)) void foo(bool x) {
+ if (__builtin_expect(x, false))
+ bar(x);
+}
diff --git a/lib/tsan/benchmarks/mop.cc b/lib/tsan/benchmarks/mop.cc
new file mode 100644
index 0000000000000..e87fab8569691
--- /dev/null
+++ b/lib/tsan/benchmarks/mop.cc
@@ -0,0 +1,80 @@
+// Synthetic benchmark for __tsan_read/write{1,2,4,8}.
+// As compared to mini_bench_local/shared.cc this benchmark passes through
+// deduplication logic (ContainsSameAccess).
+// First argument is access size (1, 2, 4, 8). Second optional arg switches
+// from writes to reads.
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+
+template<typename T, bool write>
+void* thread(void *arg) {
+ const int kSize = 2 << 10;
+ static volatile long data[kSize];
+ static volatile long turn;
+ const int kRepeat = 1 << 17;
+ const int id = !!arg;
+ for (int i = 0; i < kRepeat; i++) {
+ for (;;) {
+ int t = __atomic_load_n(&turn, __ATOMIC_ACQUIRE);
+ if (t == id)
+ break;
+ syscall(SYS_futex, &turn, FUTEX_WAIT, t, 0, 0, 0);
+ }
+ for (int j = 0; j < kSize; j++) {
+ if (write) {
+ ((volatile T*)&data[j])[0] = 1;
+ ((volatile T*)&data[j])[sizeof(T) == 8 ? 0 : 1] = 1;
+ } else {
+ T v0 = ((volatile T*)&data[j])[0];
+ T v1 = ((volatile T*)&data[j])[sizeof(T) == 8 ? 0 : 1];
+ (void)v0;
+ (void)v1;
+ }
+ }
+ __atomic_store_n(&turn, 1 - id, __ATOMIC_RELEASE);
+ syscall(SYS_futex, &turn, FUTEX_WAKE, 0, 0, 0, 0);
+ }
+ return 0;
+}
+
+template<typename T, bool write>
+void test() {
+ pthread_t th;
+ pthread_create(&th, 0, thread<T, write>, (void*)1);
+ thread<T, write>(0);
+ pthread_join(th, 0);
+}
+
+template<bool write>
+void testw(int size) {
+ switch (size) {
+ case 1: return test<char, write>();
+ case 2: return test<short, write>();
+ case 4: return test<int, write>();
+ case 8: return test<long long, write>();
+ }
+}
+
+int main(int argc, char** argv) {
+ int size = 8;
+ bool write = true;
+ if (argc > 1) {
+ size = atoi(argv[1]);
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ size = 8;
+ }
+ if (argc > 2)
+ write = false;
+ printf("%s%d\n", write ? "write" : "read", size);
+ if (write)
+ testw<true>(size);
+ else
+ testw<false>(size);
+ return 0;
+}