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