1231457ecSDavidlohr Bueso // SPDX-License-Identifier: GPL-2.0 2231457ecSDavidlohr Bueso /* 3231457ecSDavidlohr Bueso * Copyright (C) 2018 Davidlohr Bueso. 4231457ecSDavidlohr Bueso * 5231457ecSDavidlohr Bueso * Benchmark the various operations allowed for epoll_ctl(2). 6231457ecSDavidlohr Bueso * The idea is to concurrently stress a single epoll instance 7231457ecSDavidlohr Bueso */ 8231457ecSDavidlohr Bueso #ifdef HAVE_EVENTFD 9231457ecSDavidlohr Bueso /* For the CLR_() macros */ 10231457ecSDavidlohr Bueso #include <string.h> 11231457ecSDavidlohr Bueso #include <pthread.h> 12231457ecSDavidlohr Bueso 13231457ecSDavidlohr Bueso #include <errno.h> 14231457ecSDavidlohr Bueso #include <inttypes.h> 15231457ecSDavidlohr Bueso #include <signal.h> 16231457ecSDavidlohr Bueso #include <stdlib.h> 1791854f9aSArnaldo Carvalho de Melo #include <unistd.h> 18231457ecSDavidlohr Bueso #include <linux/compiler.h> 19231457ecSDavidlohr Bueso #include <linux/kernel.h> 20231457ecSDavidlohr Bueso #include <sys/time.h> 21231457ecSDavidlohr Bueso #include <sys/resource.h> 22231457ecSDavidlohr Bueso #include <sys/epoll.h> 23231457ecSDavidlohr Bueso #include <sys/eventfd.h> 2487ffb6c6SArnaldo Carvalho de Melo #include <internal/cpumap.h> 259c3516d1SJiri Olsa #include <perf/cpumap.h> 26231457ecSDavidlohr Bueso 27231457ecSDavidlohr Bueso #include "../util/stat.h" 28231457ecSDavidlohr Bueso #include <subcmd/parse-options.h> 29231457ecSDavidlohr Bueso #include "bench.h" 30231457ecSDavidlohr Bueso 31231457ecSDavidlohr Bueso #include <err.h> 32231457ecSDavidlohr Bueso 33231457ecSDavidlohr Bueso #define printinfo(fmt, arg...) \ 34231457ecSDavidlohr Bueso do { if (__verbose) printf(fmt, ## arg); } while (0) 35231457ecSDavidlohr Bueso 36231457ecSDavidlohr Bueso static unsigned int nthreads = 0; 37231457ecSDavidlohr Bueso static unsigned int nsecs = 8; 38231457ecSDavidlohr Bueso static bool done, __verbose, randomize; 39231457ecSDavidlohr Bueso 40231457ecSDavidlohr Bueso /* 41231457ecSDavidlohr Bueso * epoll related shared variables. 42231457ecSDavidlohr Bueso */ 43231457ecSDavidlohr Bueso 44231457ecSDavidlohr Bueso /* Maximum number of nesting allowed inside epoll sets */ 45231457ecSDavidlohr Bueso #define EPOLL_MAXNESTS 4 46231457ecSDavidlohr Bueso 47231457ecSDavidlohr Bueso enum { 48231457ecSDavidlohr Bueso OP_EPOLL_ADD, 49231457ecSDavidlohr Bueso OP_EPOLL_MOD, 50231457ecSDavidlohr Bueso OP_EPOLL_DEL, 51231457ecSDavidlohr Bueso EPOLL_NR_OPS, 52231457ecSDavidlohr Bueso }; 53231457ecSDavidlohr Bueso 54231457ecSDavidlohr Bueso static int epollfd; 55231457ecSDavidlohr Bueso static int *epollfdp; 56231457ecSDavidlohr Bueso static bool noaffinity; 57231457ecSDavidlohr Bueso static unsigned int nested = 0; 58231457ecSDavidlohr Bueso 59231457ecSDavidlohr Bueso /* amount of fds to monitor, per thread */ 60231457ecSDavidlohr Bueso static unsigned int nfds = 64; 61231457ecSDavidlohr Bueso 62231457ecSDavidlohr Bueso static pthread_mutex_t thread_lock; 63231457ecSDavidlohr Bueso static unsigned int threads_starting; 64231457ecSDavidlohr Bueso static struct stats all_stats[EPOLL_NR_OPS]; 65231457ecSDavidlohr Bueso static pthread_cond_t thread_parent, thread_worker; 66231457ecSDavidlohr Bueso 67231457ecSDavidlohr Bueso struct worker { 68231457ecSDavidlohr Bueso int tid; 69231457ecSDavidlohr Bueso pthread_t thread; 70231457ecSDavidlohr Bueso unsigned long ops[EPOLL_NR_OPS]; 71231457ecSDavidlohr Bueso int *fdmap; 72231457ecSDavidlohr Bueso }; 73231457ecSDavidlohr Bueso 74231457ecSDavidlohr Bueso static const struct option options[] = { 75231457ecSDavidlohr Bueso OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 76231457ecSDavidlohr Bueso OPT_UINTEGER('r', "runtime", &nsecs, "Specify runtime (in seconds)"), 77231457ecSDavidlohr Bueso OPT_UINTEGER('f', "nfds", &nfds, "Specify amount of file descriptors to monitor for each thread"), 78231457ecSDavidlohr Bueso OPT_BOOLEAN( 'n', "noaffinity", &noaffinity, "Disables CPU affinity"), 79231457ecSDavidlohr Bueso OPT_UINTEGER( 'N', "nested", &nested, "Nesting level epoll hierarchy (default is 0, no nesting)"), 80231457ecSDavidlohr Bueso OPT_BOOLEAN( 'R', "randomize", &randomize, "Perform random operations on random fds"), 81231457ecSDavidlohr Bueso OPT_BOOLEAN( 'v', "verbose", &__verbose, "Verbose mode"), 82231457ecSDavidlohr Bueso OPT_END() 83231457ecSDavidlohr Bueso }; 84231457ecSDavidlohr Bueso 85231457ecSDavidlohr Bueso static const char * const bench_epoll_ctl_usage[] = { 86231457ecSDavidlohr Bueso "perf bench epoll ctl <options>", 87231457ecSDavidlohr Bueso NULL 88231457ecSDavidlohr Bueso }; 89231457ecSDavidlohr Bueso 90231457ecSDavidlohr Bueso static void toggle_done(int sig __maybe_unused, 91231457ecSDavidlohr Bueso siginfo_t *info __maybe_unused, 92231457ecSDavidlohr Bueso void *uc __maybe_unused) 93231457ecSDavidlohr Bueso { 94231457ecSDavidlohr Bueso /* inform all threads that we're done for the day */ 95231457ecSDavidlohr Bueso done = true; 96e4d9b04bSArnaldo Carvalho de Melo gettimeofday(&bench__end, NULL); 97e4d9b04bSArnaldo Carvalho de Melo timersub(&bench__end, &bench__start, &bench__runtime); 98231457ecSDavidlohr Bueso } 99231457ecSDavidlohr Bueso 100231457ecSDavidlohr Bueso static void nest_epollfd(void) 101231457ecSDavidlohr Bueso { 102231457ecSDavidlohr Bueso unsigned int i; 103231457ecSDavidlohr Bueso struct epoll_event ev; 104231457ecSDavidlohr Bueso 105231457ecSDavidlohr Bueso if (nested > EPOLL_MAXNESTS) 106231457ecSDavidlohr Bueso nested = EPOLL_MAXNESTS; 107231457ecSDavidlohr Bueso printinfo("Nesting level(s): %d\n", nested); 108231457ecSDavidlohr Bueso 109231457ecSDavidlohr Bueso epollfdp = calloc(nested, sizeof(int)); 110231457ecSDavidlohr Bueso if (!epollfd) 111231457ecSDavidlohr Bueso err(EXIT_FAILURE, "calloc"); 112231457ecSDavidlohr Bueso 113231457ecSDavidlohr Bueso for (i = 0; i < nested; i++) { 114231457ecSDavidlohr Bueso epollfdp[i] = epoll_create(1); 115231457ecSDavidlohr Bueso if (epollfd < 0) 116231457ecSDavidlohr Bueso err(EXIT_FAILURE, "epoll_create"); 117231457ecSDavidlohr Bueso } 118231457ecSDavidlohr Bueso 119231457ecSDavidlohr Bueso ev.events = EPOLLHUP; /* anything */ 120231457ecSDavidlohr Bueso ev.data.u64 = i; /* any number */ 121231457ecSDavidlohr Bueso 122231457ecSDavidlohr Bueso for (i = nested - 1; i; i--) { 123231457ecSDavidlohr Bueso if (epoll_ctl(epollfdp[i - 1], EPOLL_CTL_ADD, 124231457ecSDavidlohr Bueso epollfdp[i], &ev) < 0) 125231457ecSDavidlohr Bueso err(EXIT_FAILURE, "epoll_ctl"); 126231457ecSDavidlohr Bueso } 127231457ecSDavidlohr Bueso 128231457ecSDavidlohr Bueso if (epoll_ctl(epollfd, EPOLL_CTL_ADD, *epollfdp, &ev) < 0) 129231457ecSDavidlohr Bueso err(EXIT_FAILURE, "epoll_ctl"); 130231457ecSDavidlohr Bueso } 131231457ecSDavidlohr Bueso 132231457ecSDavidlohr Bueso static inline void do_epoll_op(struct worker *w, int op, int fd) 133231457ecSDavidlohr Bueso { 134231457ecSDavidlohr Bueso int error; 135231457ecSDavidlohr Bueso struct epoll_event ev; 136231457ecSDavidlohr Bueso 137231457ecSDavidlohr Bueso ev.events = EPOLLIN; 138231457ecSDavidlohr Bueso ev.data.u64 = fd; 139231457ecSDavidlohr Bueso 140231457ecSDavidlohr Bueso switch (op) { 141231457ecSDavidlohr Bueso case OP_EPOLL_ADD: 142231457ecSDavidlohr Bueso error = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); 143231457ecSDavidlohr Bueso break; 144231457ecSDavidlohr Bueso case OP_EPOLL_MOD: 145231457ecSDavidlohr Bueso ev.events = EPOLLOUT; 146231457ecSDavidlohr Bueso error = epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev); 147231457ecSDavidlohr Bueso break; 148231457ecSDavidlohr Bueso case OP_EPOLL_DEL: 149231457ecSDavidlohr Bueso error = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL); 150231457ecSDavidlohr Bueso break; 151231457ecSDavidlohr Bueso default: 152231457ecSDavidlohr Bueso error = 1; 153231457ecSDavidlohr Bueso break; 154231457ecSDavidlohr Bueso } 155231457ecSDavidlohr Bueso 156231457ecSDavidlohr Bueso if (!error) 157231457ecSDavidlohr Bueso w->ops[op]++; 158231457ecSDavidlohr Bueso } 159231457ecSDavidlohr Bueso 160231457ecSDavidlohr Bueso static inline void do_random_epoll_op(struct worker *w) 161231457ecSDavidlohr Bueso { 162231457ecSDavidlohr Bueso unsigned long rnd1 = random(), rnd2 = random(); 163231457ecSDavidlohr Bueso int op, fd; 164231457ecSDavidlohr Bueso 165231457ecSDavidlohr Bueso fd = w->fdmap[rnd1 % nfds]; 166231457ecSDavidlohr Bueso op = rnd2 % EPOLL_NR_OPS; 167231457ecSDavidlohr Bueso 168231457ecSDavidlohr Bueso do_epoll_op(w, op, fd); 169231457ecSDavidlohr Bueso } 170231457ecSDavidlohr Bueso 171231457ecSDavidlohr Bueso static void *workerfn(void *arg) 172231457ecSDavidlohr Bueso { 173231457ecSDavidlohr Bueso unsigned int i; 174231457ecSDavidlohr Bueso struct worker *w = (struct worker *) arg; 175231457ecSDavidlohr Bueso struct timespec ts = { .tv_sec = 0, 176231457ecSDavidlohr Bueso .tv_nsec = 250 }; 177231457ecSDavidlohr Bueso 178231457ecSDavidlohr Bueso pthread_mutex_lock(&thread_lock); 179231457ecSDavidlohr Bueso threads_starting--; 180231457ecSDavidlohr Bueso if (!threads_starting) 181231457ecSDavidlohr Bueso pthread_cond_signal(&thread_parent); 182231457ecSDavidlohr Bueso pthread_cond_wait(&thread_worker, &thread_lock); 183231457ecSDavidlohr Bueso pthread_mutex_unlock(&thread_lock); 184231457ecSDavidlohr Bueso 185231457ecSDavidlohr Bueso /* Let 'em loose */ 186231457ecSDavidlohr Bueso do { 187231457ecSDavidlohr Bueso /* random */ 188231457ecSDavidlohr Bueso if (randomize) { 189231457ecSDavidlohr Bueso do_random_epoll_op(w); 190231457ecSDavidlohr Bueso } else { 191231457ecSDavidlohr Bueso for (i = 0; i < nfds; i++) { 192231457ecSDavidlohr Bueso do_epoll_op(w, OP_EPOLL_ADD, w->fdmap[i]); 193231457ecSDavidlohr Bueso do_epoll_op(w, OP_EPOLL_MOD, w->fdmap[i]); 194231457ecSDavidlohr Bueso do_epoll_op(w, OP_EPOLL_DEL, w->fdmap[i]); 195231457ecSDavidlohr Bueso } 196231457ecSDavidlohr Bueso } 197231457ecSDavidlohr Bueso 198231457ecSDavidlohr Bueso nanosleep(&ts, NULL); 199231457ecSDavidlohr Bueso } while (!done); 200231457ecSDavidlohr Bueso 201231457ecSDavidlohr Bueso return NULL; 202231457ecSDavidlohr Bueso } 203231457ecSDavidlohr Bueso 204231457ecSDavidlohr Bueso static void init_fdmaps(struct worker *w, int pct) 205231457ecSDavidlohr Bueso { 206231457ecSDavidlohr Bueso unsigned int i; 207231457ecSDavidlohr Bueso int inc; 208231457ecSDavidlohr Bueso struct epoll_event ev; 209231457ecSDavidlohr Bueso 210231457ecSDavidlohr Bueso if (!pct) 211231457ecSDavidlohr Bueso return; 212231457ecSDavidlohr Bueso 213231457ecSDavidlohr Bueso inc = 100/pct; 214231457ecSDavidlohr Bueso for (i = 0; i < nfds; i+=inc) { 215231457ecSDavidlohr Bueso ev.data.fd = w->fdmap[i]; 216231457ecSDavidlohr Bueso ev.events = EPOLLIN; 217231457ecSDavidlohr Bueso 218231457ecSDavidlohr Bueso if (epoll_ctl(epollfd, EPOLL_CTL_ADD, w->fdmap[i], &ev) < 0) 219231457ecSDavidlohr Bueso err(EXIT_FAILURE, "epoll_ct"); 220231457ecSDavidlohr Bueso } 221231457ecSDavidlohr Bueso } 222231457ecSDavidlohr Bueso 223f854839bSJiri Olsa static int do_threads(struct worker *worker, struct perf_cpu_map *cpu) 224231457ecSDavidlohr Bueso { 225231457ecSDavidlohr Bueso pthread_attr_t thread_attr, *attrp = NULL; 226231457ecSDavidlohr Bueso cpu_set_t cpuset; 227231457ecSDavidlohr Bueso unsigned int i, j; 22811c1ea6fSChangbin Du int ret = 0; 229231457ecSDavidlohr Bueso 230231457ecSDavidlohr Bueso if (!noaffinity) 231231457ecSDavidlohr Bueso pthread_attr_init(&thread_attr); 232231457ecSDavidlohr Bueso 233231457ecSDavidlohr Bueso for (i = 0; i < nthreads; i++) { 234231457ecSDavidlohr Bueso struct worker *w = &worker[i]; 235231457ecSDavidlohr Bueso 236231457ecSDavidlohr Bueso w->tid = i; 237231457ecSDavidlohr Bueso w->fdmap = calloc(nfds, sizeof(int)); 238231457ecSDavidlohr Bueso if (!w->fdmap) 239231457ecSDavidlohr Bueso return 1; 240231457ecSDavidlohr Bueso 241231457ecSDavidlohr Bueso for (j = 0; j < nfds; j++) { 242231457ecSDavidlohr Bueso w->fdmap[j] = eventfd(0, EFD_NONBLOCK); 243231457ecSDavidlohr Bueso if (w->fdmap[j] < 0) 244231457ecSDavidlohr Bueso err(EXIT_FAILURE, "eventfd"); 245231457ecSDavidlohr Bueso } 246231457ecSDavidlohr Bueso 247231457ecSDavidlohr Bueso /* 248231457ecSDavidlohr Bueso * Lets add 50% of the fdmap to the epoll instance, and 249231457ecSDavidlohr Bueso * do it before any threads are started; otherwise there is 250231457ecSDavidlohr Bueso * an initial bias of the call failing (mod and del ops). 251231457ecSDavidlohr Bueso */ 252231457ecSDavidlohr Bueso if (randomize) 253231457ecSDavidlohr Bueso init_fdmaps(w, 50); 254231457ecSDavidlohr Bueso 255231457ecSDavidlohr Bueso if (!noaffinity) { 256231457ecSDavidlohr Bueso CPU_ZERO(&cpuset); 257231457ecSDavidlohr Bueso CPU_SET(cpu->map[i % cpu->nr], &cpuset); 258231457ecSDavidlohr Bueso 259231457ecSDavidlohr Bueso ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpuset); 260231457ecSDavidlohr Bueso if (ret) 261231457ecSDavidlohr Bueso err(EXIT_FAILURE, "pthread_attr_setaffinity_np"); 262231457ecSDavidlohr Bueso 263231457ecSDavidlohr Bueso attrp = &thread_attr; 264231457ecSDavidlohr Bueso } 265231457ecSDavidlohr Bueso 266231457ecSDavidlohr Bueso ret = pthread_create(&w->thread, attrp, workerfn, 267231457ecSDavidlohr Bueso (void *)(struct worker *) w); 268231457ecSDavidlohr Bueso if (ret) 269231457ecSDavidlohr Bueso err(EXIT_FAILURE, "pthread_create"); 270231457ecSDavidlohr Bueso } 271231457ecSDavidlohr Bueso 272231457ecSDavidlohr Bueso if (!noaffinity) 273231457ecSDavidlohr Bueso pthread_attr_destroy(&thread_attr); 274231457ecSDavidlohr Bueso 275231457ecSDavidlohr Bueso return ret; 276231457ecSDavidlohr Bueso } 277231457ecSDavidlohr Bueso 278231457ecSDavidlohr Bueso static void print_summary(void) 279231457ecSDavidlohr Bueso { 280231457ecSDavidlohr Bueso int i; 281231457ecSDavidlohr Bueso unsigned long avg[EPOLL_NR_OPS]; 282231457ecSDavidlohr Bueso double stddev[EPOLL_NR_OPS]; 283231457ecSDavidlohr Bueso 284231457ecSDavidlohr Bueso for (i = 0; i < EPOLL_NR_OPS; i++) { 285231457ecSDavidlohr Bueso avg[i] = avg_stats(&all_stats[i]); 286231457ecSDavidlohr Bueso stddev[i] = stddev_stats(&all_stats[i]); 287231457ecSDavidlohr Bueso } 288231457ecSDavidlohr Bueso 289231457ecSDavidlohr Bueso printf("\nAveraged %ld ADD operations (+- %.2f%%)\n", 290231457ecSDavidlohr Bueso avg[OP_EPOLL_ADD], rel_stddev_stats(stddev[OP_EPOLL_ADD], 291231457ecSDavidlohr Bueso avg[OP_EPOLL_ADD])); 292231457ecSDavidlohr Bueso printf("Averaged %ld MOD operations (+- %.2f%%)\n", 293231457ecSDavidlohr Bueso avg[OP_EPOLL_MOD], rel_stddev_stats(stddev[OP_EPOLL_MOD], 294231457ecSDavidlohr Bueso avg[OP_EPOLL_MOD])); 295231457ecSDavidlohr Bueso printf("Averaged %ld DEL operations (+- %.2f%%)\n", 296231457ecSDavidlohr Bueso avg[OP_EPOLL_DEL], rel_stddev_stats(stddev[OP_EPOLL_DEL], 297231457ecSDavidlohr Bueso avg[OP_EPOLL_DEL])); 298231457ecSDavidlohr Bueso } 299231457ecSDavidlohr Bueso 300231457ecSDavidlohr Bueso int bench_epoll_ctl(int argc, const char **argv) 301231457ecSDavidlohr Bueso { 302231457ecSDavidlohr Bueso int j, ret = 0; 303231457ecSDavidlohr Bueso struct sigaction act; 304231457ecSDavidlohr Bueso struct worker *worker = NULL; 305f854839bSJiri Olsa struct perf_cpu_map *cpu; 306231457ecSDavidlohr Bueso struct rlimit rl, prevrl; 307231457ecSDavidlohr Bueso unsigned int i; 308231457ecSDavidlohr Bueso 309231457ecSDavidlohr Bueso argc = parse_options(argc, argv, options, bench_epoll_ctl_usage, 0); 310231457ecSDavidlohr Bueso if (argc) { 311231457ecSDavidlohr Bueso usage_with_options(bench_epoll_ctl_usage, options); 312231457ecSDavidlohr Bueso exit(EXIT_FAILURE); 313231457ecSDavidlohr Bueso } 314231457ecSDavidlohr Bueso 3157b919a53STommi Rantala memset(&act, 0, sizeof(act)); 316231457ecSDavidlohr Bueso sigfillset(&act.sa_mask); 317231457ecSDavidlohr Bueso act.sa_sigaction = toggle_done; 318231457ecSDavidlohr Bueso sigaction(SIGINT, &act, NULL); 319231457ecSDavidlohr Bueso 3209c3516d1SJiri Olsa cpu = perf_cpu_map__new(NULL); 321231457ecSDavidlohr Bueso if (!cpu) 322231457ecSDavidlohr Bueso goto errmem; 323231457ecSDavidlohr Bueso 324231457ecSDavidlohr Bueso /* a single, main epoll instance */ 325231457ecSDavidlohr Bueso epollfd = epoll_create(1); 326231457ecSDavidlohr Bueso if (epollfd < 0) 327231457ecSDavidlohr Bueso err(EXIT_FAILURE, "epoll_create"); 328231457ecSDavidlohr Bueso 329231457ecSDavidlohr Bueso /* 330231457ecSDavidlohr Bueso * Deal with nested epolls, if any. 331231457ecSDavidlohr Bueso */ 332231457ecSDavidlohr Bueso if (nested) 333231457ecSDavidlohr Bueso nest_epollfd(); 334231457ecSDavidlohr Bueso 335231457ecSDavidlohr Bueso /* default to the number of CPUs */ 336231457ecSDavidlohr Bueso if (!nthreads) 337231457ecSDavidlohr Bueso nthreads = cpu->nr; 338231457ecSDavidlohr Bueso 339231457ecSDavidlohr Bueso worker = calloc(nthreads, sizeof(*worker)); 340231457ecSDavidlohr Bueso if (!worker) 341231457ecSDavidlohr Bueso goto errmem; 342231457ecSDavidlohr Bueso 343231457ecSDavidlohr Bueso if (getrlimit(RLIMIT_NOFILE, &prevrl)) 344231457ecSDavidlohr Bueso err(EXIT_FAILURE, "getrlimit"); 345231457ecSDavidlohr Bueso rl.rlim_cur = rl.rlim_max = nfds * nthreads * 2 + 50; 346231457ecSDavidlohr Bueso printinfo("Setting RLIMIT_NOFILE rlimit from %" PRIu64 " to: %" PRIu64 "\n", 347231457ecSDavidlohr Bueso (uint64_t)prevrl.rlim_max, (uint64_t)rl.rlim_max); 348231457ecSDavidlohr Bueso if (setrlimit(RLIMIT_NOFILE, &rl) < 0) 349231457ecSDavidlohr Bueso err(EXIT_FAILURE, "setrlimit"); 350231457ecSDavidlohr Bueso 351231457ecSDavidlohr Bueso printf("Run summary [PID %d]: %d threads doing epoll_ctl ops " 352231457ecSDavidlohr Bueso "%d file-descriptors for %d secs.\n\n", 353231457ecSDavidlohr Bueso getpid(), nthreads, nfds, nsecs); 354231457ecSDavidlohr Bueso 355231457ecSDavidlohr Bueso for (i = 0; i < EPOLL_NR_OPS; i++) 356231457ecSDavidlohr Bueso init_stats(&all_stats[i]); 357231457ecSDavidlohr Bueso 358231457ecSDavidlohr Bueso pthread_mutex_init(&thread_lock, NULL); 359231457ecSDavidlohr Bueso pthread_cond_init(&thread_parent, NULL); 360231457ecSDavidlohr Bueso pthread_cond_init(&thread_worker, NULL); 361231457ecSDavidlohr Bueso 362231457ecSDavidlohr Bueso threads_starting = nthreads; 363231457ecSDavidlohr Bueso 364e4d9b04bSArnaldo Carvalho de Melo gettimeofday(&bench__start, NULL); 365231457ecSDavidlohr Bueso 366231457ecSDavidlohr Bueso do_threads(worker, cpu); 367231457ecSDavidlohr Bueso 368231457ecSDavidlohr Bueso pthread_mutex_lock(&thread_lock); 369231457ecSDavidlohr Bueso while (threads_starting) 370231457ecSDavidlohr Bueso pthread_cond_wait(&thread_parent, &thread_lock); 371231457ecSDavidlohr Bueso pthread_cond_broadcast(&thread_worker); 372231457ecSDavidlohr Bueso pthread_mutex_unlock(&thread_lock); 373231457ecSDavidlohr Bueso 374231457ecSDavidlohr Bueso sleep(nsecs); 375231457ecSDavidlohr Bueso toggle_done(0, NULL, NULL); 376231457ecSDavidlohr Bueso printinfo("main thread: toggling done\n"); 377231457ecSDavidlohr Bueso 378231457ecSDavidlohr Bueso for (i = 0; i < nthreads; i++) { 379231457ecSDavidlohr Bueso ret = pthread_join(worker[i].thread, NULL); 380231457ecSDavidlohr Bueso if (ret) 381231457ecSDavidlohr Bueso err(EXIT_FAILURE, "pthread_join"); 382231457ecSDavidlohr Bueso } 383231457ecSDavidlohr Bueso 384231457ecSDavidlohr Bueso /* cleanup & report results */ 385231457ecSDavidlohr Bueso pthread_cond_destroy(&thread_parent); 386231457ecSDavidlohr Bueso pthread_cond_destroy(&thread_worker); 387231457ecSDavidlohr Bueso pthread_mutex_destroy(&thread_lock); 388231457ecSDavidlohr Bueso 389231457ecSDavidlohr Bueso for (i = 0; i < nthreads; i++) { 390231457ecSDavidlohr Bueso unsigned long t[EPOLL_NR_OPS]; 391231457ecSDavidlohr Bueso 392231457ecSDavidlohr Bueso for (j = 0; j < EPOLL_NR_OPS; j++) { 393231457ecSDavidlohr Bueso t[j] = worker[i].ops[j]; 394231457ecSDavidlohr Bueso update_stats(&all_stats[j], t[j]); 395231457ecSDavidlohr Bueso } 396231457ecSDavidlohr Bueso 397231457ecSDavidlohr Bueso if (nfds == 1) 398231457ecSDavidlohr Bueso printf("[thread %2d] fdmap: %p [ add: %04ld; mod: %04ld; del: %04lds ops ]\n", 399231457ecSDavidlohr Bueso worker[i].tid, &worker[i].fdmap[0], 400231457ecSDavidlohr Bueso t[OP_EPOLL_ADD], t[OP_EPOLL_MOD], t[OP_EPOLL_DEL]); 401231457ecSDavidlohr Bueso else 402231457ecSDavidlohr Bueso printf("[thread %2d] fdmap: %p ... %p [ add: %04ld ops; mod: %04ld ops; del: %04ld ops ]\n", 403231457ecSDavidlohr Bueso worker[i].tid, &worker[i].fdmap[0], 404231457ecSDavidlohr Bueso &worker[i].fdmap[nfds-1], 405231457ecSDavidlohr Bueso t[OP_EPOLL_ADD], t[OP_EPOLL_MOD], t[OP_EPOLL_DEL]); 406231457ecSDavidlohr Bueso } 407231457ecSDavidlohr Bueso 408231457ecSDavidlohr Bueso print_summary(); 409231457ecSDavidlohr Bueso 410231457ecSDavidlohr Bueso close(epollfd); 411231457ecSDavidlohr Bueso return ret; 412231457ecSDavidlohr Bueso errmem: 413231457ecSDavidlohr Bueso err(EXIT_FAILURE, "calloc"); 414231457ecSDavidlohr Bueso } 415231457ecSDavidlohr Bueso #endif // HAVE_EVENTFD 416