// 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 #include #include #include #include #include #include template 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 void test() { pthread_t th; pthread_create(&th, 0, thread, (void*)1); thread(0); pthread_join(th, 0); } template void testw(int size) { switch (size) { case 1: return test(); case 2: return test(); case 4: return test(); case 8: return test(); } } 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(size); else testw(size); return 0; }