xref: /openbsd-src/gnu/llvm/compiler-rt/lib/tsan/benchmarks/mop.cpp (revision 3cab2bb3f667058bece8e38b12449a63a9d73c4b)
1*3cab2bb3Spatrick // Synthetic benchmark for __tsan_read/write{1,2,4,8}.
2*3cab2bb3Spatrick // As compared to mini_bench_local/shared.cc this benchmark passes through
3*3cab2bb3Spatrick // deduplication logic (ContainsSameAccess).
4*3cab2bb3Spatrick // First argument is access size (1, 2, 4, 8). Second optional arg switches
5*3cab2bb3Spatrick // from writes to reads.
6*3cab2bb3Spatrick 
7*3cab2bb3Spatrick #include <pthread.h>
8*3cab2bb3Spatrick #include <stdlib.h>
9*3cab2bb3Spatrick #include <stdio.h>
10*3cab2bb3Spatrick #include <unistd.h>
11*3cab2bb3Spatrick #include <linux/futex.h>
12*3cab2bb3Spatrick #include <sys/syscall.h>
13*3cab2bb3Spatrick #include <sys/time.h>
14*3cab2bb3Spatrick 
15*3cab2bb3Spatrick template<typename T, bool write>
thread(void * arg)16*3cab2bb3Spatrick void* thread(void *arg) {
17*3cab2bb3Spatrick   const int kSize = 2 << 10;
18*3cab2bb3Spatrick   static volatile long data[kSize];
19*3cab2bb3Spatrick   static volatile long turn;
20*3cab2bb3Spatrick   const int kRepeat = 1 << 17;
21*3cab2bb3Spatrick   const int id = !!arg;
22*3cab2bb3Spatrick   for (int i = 0; i < kRepeat; i++) {
23*3cab2bb3Spatrick     for (;;) {
24*3cab2bb3Spatrick       int t = __atomic_load_n(&turn, __ATOMIC_ACQUIRE);
25*3cab2bb3Spatrick       if (t == id)
26*3cab2bb3Spatrick         break;
27*3cab2bb3Spatrick       syscall(SYS_futex, &turn, FUTEX_WAIT, t, 0, 0, 0);
28*3cab2bb3Spatrick     }
29*3cab2bb3Spatrick     for (int j = 0; j < kSize; j++) {
30*3cab2bb3Spatrick       if (write) {
31*3cab2bb3Spatrick         ((volatile T*)&data[j])[0] = 1;
32*3cab2bb3Spatrick         ((volatile T*)&data[j])[sizeof(T) == 8 ? 0 : 1] = 1;
33*3cab2bb3Spatrick       } else {
34*3cab2bb3Spatrick         T v0 = ((volatile T*)&data[j])[0];
35*3cab2bb3Spatrick         T v1 = ((volatile T*)&data[j])[sizeof(T) == 8 ? 0 : 1];
36*3cab2bb3Spatrick         (void)v0;
37*3cab2bb3Spatrick         (void)v1;
38*3cab2bb3Spatrick       }
39*3cab2bb3Spatrick     }
40*3cab2bb3Spatrick     __atomic_store_n(&turn, 1 - id, __ATOMIC_RELEASE);
41*3cab2bb3Spatrick     syscall(SYS_futex, &turn, FUTEX_WAKE, 0, 0, 0, 0);
42*3cab2bb3Spatrick   }
43*3cab2bb3Spatrick   return 0;
44*3cab2bb3Spatrick }
45*3cab2bb3Spatrick 
46*3cab2bb3Spatrick template<typename T, bool write>
test()47*3cab2bb3Spatrick void test() {
48*3cab2bb3Spatrick   pthread_t th;
49*3cab2bb3Spatrick   pthread_create(&th, 0, thread<T, write>, (void*)1);
50*3cab2bb3Spatrick   thread<T, write>(0);
51*3cab2bb3Spatrick   pthread_join(th, 0);
52*3cab2bb3Spatrick }
53*3cab2bb3Spatrick 
54*3cab2bb3Spatrick template<bool write>
testw(int size)55*3cab2bb3Spatrick void testw(int size) {
56*3cab2bb3Spatrick   switch (size) {
57*3cab2bb3Spatrick   case 1: return test<char, write>();
58*3cab2bb3Spatrick   case 2: return test<short, write>();
59*3cab2bb3Spatrick   case 4: return test<int, write>();
60*3cab2bb3Spatrick   case 8: return test<long long, write>();
61*3cab2bb3Spatrick   }
62*3cab2bb3Spatrick }
63*3cab2bb3Spatrick 
main(int argc,char ** argv)64*3cab2bb3Spatrick int main(int argc, char** argv) {
65*3cab2bb3Spatrick   int size = 8;
66*3cab2bb3Spatrick   bool write = true;
67*3cab2bb3Spatrick   if (argc > 1) {
68*3cab2bb3Spatrick     size = atoi(argv[1]);
69*3cab2bb3Spatrick     if (size != 1 && size != 2 && size != 4 && size != 8)
70*3cab2bb3Spatrick       size = 8;
71*3cab2bb3Spatrick   }
72*3cab2bb3Spatrick   if (argc > 2)
73*3cab2bb3Spatrick     write = false;
74*3cab2bb3Spatrick   printf("%s%d\n", write ? "write" : "read", size);
75*3cab2bb3Spatrick   if (write)
76*3cab2bb3Spatrick     testw<true>(size);
77*3cab2bb3Spatrick   else
78*3cab2bb3Spatrick     testw<false>(size);
79*3cab2bb3Spatrick   return 0;
80*3cab2bb3Spatrick }
81