1 | #include <pthread.h> |
2 | #include <stdlib.h> |
3 | #include <stddef.h> |
4 | #include <unistd.h> |
5 | #include <stdio.h> |
6 | #include <time.h> |
7 | |
8 | int bench_nthread; |
9 | int bench_niter; |
10 | int grow_clock_var; |
11 | pthread_barrier_t glow_clock_barrier; |
12 | |
13 | void bench(); // defined by user |
14 | void start_thread_group(int nth, void(*f)(int tid)); |
15 | void grow_clock_worker(int tid); |
16 | |
17 | int main(int argc, char **argv) { |
18 | bench_nthread = 2; |
19 | if (argc > 1) |
20 | bench_nthread = atoi(argv[1]); |
21 | bench_niter = 100; |
22 | if (argc > 2) |
23 | bench_niter = atoi(argv[2]); |
24 | |
25 | // Grow thread's clock. |
26 | int clock_size = 10; |
27 | if (argc > 1) |
28 | clock_size = 1000; |
29 | pthread_barrier_init(&glow_clock_barrier, 0, clock_size); |
30 | start_thread_group(clock_size, grow_clock_worker); |
31 | pthread_barrier_destroy(&glow_clock_barrier); |
32 | __atomic_load_n(&grow_clock_var, __ATOMIC_ACQUIRE); |
33 | |
34 | timespec tp0; |
35 | clock_gettime(CLOCK_MONOTONIC, &tp0); |
36 | bench(); |
37 | timespec tp1; |
38 | clock_gettime(CLOCK_MONOTONIC, &tp1); |
39 | unsigned long long t = |
40 | (tp1.tv_sec * 1000000000ULL + tp1.tv_nsec) - |
41 | (tp0.tv_sec * 1000000000ULL + tp0.tv_nsec); |
42 | fprintf(stderr, "%llu ns/iter\n" , t / bench_niter); |
43 | fprintf(stderr, "DONE\n" ); |
44 | } |
45 | |
46 | void start_thread_group(int nth, void(*f)(int tid)) { |
47 | pthread_t *th = (pthread_t*)malloc(nth * sizeof(pthread_t)); |
48 | for (int i = 0; i < nth; i++) |
49 | pthread_create(&th[i], 0, (void*(*)(void*))f, (void*)(long)i); |
50 | for (int i = 0; i < nth; i++) |
51 | pthread_join(th[i], 0); |
52 | } |
53 | |
54 | void grow_clock_worker(int tid) { |
55 | int res = pthread_barrier_wait(&glow_clock_barrier); |
56 | if (res == PTHREAD_BARRIER_SERIAL_THREAD) |
57 | __atomic_store_n(&grow_clock_var, 0, __ATOMIC_RELEASE); |
58 | } |
59 | |
60 | |