| #include <pthread.h> |
| #include <stdlib.h> |
| #include <stddef.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <time.h> |
| |
| int bench_nthread; |
| int bench_niter; |
| int grow_clock_var; |
| pthread_barrier_t glow_clock_barrier; |
| |
| void bench(); // defined by user |
| void start_thread_group(int nth, void(*f)(int tid)); |
| void grow_clock_worker(int tid); |
| |
| int main(int argc, char **argv) { |
| bench_nthread = 2; |
| if (argc > 1) |
| bench_nthread = atoi(argv[1]); |
| bench_niter = 100; |
| if (argc > 2) |
| bench_niter = atoi(argv[2]); |
| |
| // Grow thread's clock. |
| int clock_size = 10; |
| if (argc > 1) |
| clock_size = 1000; |
| pthread_barrier_init(&glow_clock_barrier, 0, clock_size); |
| start_thread_group(clock_size, grow_clock_worker); |
| pthread_barrier_destroy(&glow_clock_barrier); |
| __atomic_load_n(&grow_clock_var, __ATOMIC_ACQUIRE); |
| |
| timespec tp0; |
| clock_gettime(CLOCK_MONOTONIC, &tp0); |
| bench(); |
| timespec tp1; |
| clock_gettime(CLOCK_MONOTONIC, &tp1); |
| unsigned long long t = |
| (tp1.tv_sec * 1000000000ULL + tp1.tv_nsec) - |
| (tp0.tv_sec * 1000000000ULL + tp0.tv_nsec); |
| fprintf(stderr, "%llu ns/iter\n", t / bench_niter); |
| fprintf(stderr, "DONE\n"); |
| } |
| |
| void start_thread_group(int nth, void(*f)(int tid)) { |
| pthread_t *th = (pthread_t*)malloc(nth * sizeof(pthread_t)); |
| for (int i = 0; i < nth; i++) |
| pthread_create(&th[i], 0, (void*(*)(void*))f, (void*)(long)i); |
| for (int i = 0; i < nth; i++) |
| pthread_join(th[i], 0); |
| } |
| |
| void grow_clock_worker(int tid) { |
| int res = pthread_barrier_wait(&glow_clock_barrier); |
| if (res == PTHREAD_BARRIER_SERIAL_THREAD) |
| __atomic_store_n(&grow_clock_var, 0, __ATOMIC_RELEASE); |
| } |
| |