1353944Sdim// Synthetic benchmark for __tsan_read/write{1,2,4,8}. 2353944Sdim// As compared to mini_bench_local/shared.cc this benchmark passes through 3353944Sdim// deduplication logic (ContainsSameAccess). 4353944Sdim// First argument is access size (1, 2, 4, 8). Second optional arg switches 5353944Sdim// from writes to reads. 6353944Sdim 7353944Sdim#include <pthread.h> 8353944Sdim#include <stdlib.h> 9353944Sdim#include <stdio.h> 10353944Sdim#include <unistd.h> 11353944Sdim#include <linux/futex.h> 12353944Sdim#include <sys/syscall.h> 13353944Sdim#include <sys/time.h> 14353944Sdim 15353944Sdimtemplate<typename T, bool write> 16353944Sdimvoid* thread(void *arg) { 17353944Sdim const int kSize = 2 << 10; 18353944Sdim static volatile long data[kSize]; 19353944Sdim static volatile long turn; 20353944Sdim const int kRepeat = 1 << 17; 21353944Sdim const int id = !!arg; 22353944Sdim for (int i = 0; i < kRepeat; i++) { 23353944Sdim for (;;) { 24353944Sdim int t = __atomic_load_n(&turn, __ATOMIC_ACQUIRE); 25353944Sdim if (t == id) 26353944Sdim break; 27353944Sdim syscall(SYS_futex, &turn, FUTEX_WAIT, t, 0, 0, 0); 28353944Sdim } 29353944Sdim for (int j = 0; j < kSize; j++) { 30353944Sdim if (write) { 31353944Sdim ((volatile T*)&data[j])[0] = 1; 32353944Sdim ((volatile T*)&data[j])[sizeof(T) == 8 ? 0 : 1] = 1; 33353944Sdim } else { 34353944Sdim T v0 = ((volatile T*)&data[j])[0]; 35353944Sdim T v1 = ((volatile T*)&data[j])[sizeof(T) == 8 ? 0 : 1]; 36353944Sdim (void)v0; 37353944Sdim (void)v1; 38353944Sdim } 39353944Sdim } 40353944Sdim __atomic_store_n(&turn, 1 - id, __ATOMIC_RELEASE); 41353944Sdim syscall(SYS_futex, &turn, FUTEX_WAKE, 0, 0, 0, 0); 42353944Sdim } 43353944Sdim return 0; 44353944Sdim} 45353944Sdim 46353944Sdimtemplate<typename T, bool write> 47353944Sdimvoid test() { 48353944Sdim pthread_t th; 49353944Sdim pthread_create(&th, 0, thread<T, write>, (void*)1); 50353944Sdim thread<T, write>(0); 51353944Sdim pthread_join(th, 0); 52353944Sdim} 53353944Sdim 54353944Sdimtemplate<bool write> 55353944Sdimvoid testw(int size) { 56353944Sdim switch (size) { 57353944Sdim case 1: return test<char, write>(); 58353944Sdim case 2: return test<short, write>(); 59353944Sdim case 4: return test<int, write>(); 60353944Sdim case 8: return test<long long, write>(); 61353944Sdim } 62353944Sdim} 63353944Sdim 64353944Sdimint main(int argc, char** argv) { 65353944Sdim int size = 8; 66353944Sdim bool write = true; 67353944Sdim if (argc > 1) { 68353944Sdim size = atoi(argv[1]); 69353944Sdim if (size != 1 && size != 2 && size != 4 && size != 8) 70353944Sdim size = 8; 71353944Sdim } 72353944Sdim if (argc > 2) 73353944Sdim write = false; 74353944Sdim printf("%s%d\n", write ? "write" : "read", size); 75353944Sdim if (write) 76353944Sdim testw<true>(size); 77353944Sdim else 78353944Sdim testw<false>(size); 79353944Sdim return 0; 80353944Sdim} 81