Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.5-rc7 219 lines 5.4 kB view raw
1/* 2 * Copyright (C) 2015 Davidlohr Bueso. 3 */ 4 5#include "../perf.h" 6#include "../util/util.h" 7#include "../util/stat.h" 8#include <subcmd/parse-options.h> 9#include "../util/header.h" 10#include "bench.h" 11#include "futex.h" 12 13#include <err.h> 14#include <stdlib.h> 15#include <sys/time.h> 16#include <pthread.h> 17 18struct worker { 19 int tid; 20 u_int32_t *futex; 21 pthread_t thread; 22 unsigned long ops; 23}; 24 25static u_int32_t global_futex = 0; 26static struct worker *worker; 27static unsigned int nsecs = 10; 28static bool silent = false, multi = false; 29static bool done = false, fshared = false; 30static unsigned int ncpus, nthreads = 0; 31static int futex_flag = 0; 32struct timeval start, end, runtime; 33static pthread_mutex_t thread_lock; 34static unsigned int threads_starting; 35static struct stats throughput_stats; 36static pthread_cond_t thread_parent, thread_worker; 37 38static const struct option options[] = { 39 OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), 40 OPT_UINTEGER('r', "runtime", &nsecs, "Specify runtime (in seconds)"), 41 OPT_BOOLEAN( 'M', "multi", &multi, "Use multiple futexes"), 42 OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), 43 OPT_BOOLEAN( 'S', "shared", &fshared, "Use shared futexes instead of private ones"), 44 OPT_END() 45}; 46 47static const char * const bench_futex_lock_pi_usage[] = { 48 "perf bench futex requeue <options>", 49 NULL 50}; 51 52static void print_summary(void) 53{ 54 unsigned long avg = avg_stats(&throughput_stats); 55 double stddev = stddev_stats(&throughput_stats); 56 57 printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n", 58 !silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg), 59 (int) runtime.tv_sec); 60} 61 62static void toggle_done(int sig __maybe_unused, 63 siginfo_t *info __maybe_unused, 64 void *uc __maybe_unused) 65{ 66 /* inform all threads that we're done for the day */ 67 done = true; 68 gettimeofday(&end, NULL); 69 timersub(&end, &start, &runtime); 70} 71 72static void *workerfn(void *arg) 73{ 74 struct worker *w = (struct worker *) arg; 75 76 pthread_mutex_lock(&thread_lock); 77 threads_starting--; 78 if (!threads_starting) 79 pthread_cond_signal(&thread_parent); 80 pthread_cond_wait(&thread_worker, &thread_lock); 81 pthread_mutex_unlock(&thread_lock); 82 83 do { 84 int ret; 85 again: 86 ret = futex_lock_pi(w->futex, NULL, 0, futex_flag); 87 88 if (ret) { /* handle lock acquisition */ 89 if (!silent) 90 warn("thread %d: Could not lock pi-lock for %p (%d)", 91 w->tid, w->futex, ret); 92 if (done) 93 break; 94 95 goto again; 96 } 97 98 usleep(1); 99 ret = futex_unlock_pi(w->futex, futex_flag); 100 if (ret && !silent) 101 warn("thread %d: Could not unlock pi-lock for %p (%d)", 102 w->tid, w->futex, ret); 103 w->ops++; /* account for thread's share of work */ 104 } while (!done); 105 106 return NULL; 107} 108 109static void create_threads(struct worker *w, pthread_attr_t thread_attr) 110{ 111 cpu_set_t cpu; 112 unsigned int i; 113 114 threads_starting = nthreads; 115 116 for (i = 0; i < nthreads; i++) { 117 worker[i].tid = i; 118 119 if (multi) { 120 worker[i].futex = calloc(1, sizeof(u_int32_t)); 121 if (!worker[i].futex) 122 err(EXIT_FAILURE, "calloc"); 123 } else 124 worker[i].futex = &global_futex; 125 126 CPU_ZERO(&cpu); 127 CPU_SET(i % ncpus, &cpu); 128 129 if (pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu)) 130 err(EXIT_FAILURE, "pthread_attr_setaffinity_np"); 131 132 if (pthread_create(&w[i].thread, &thread_attr, workerfn, &worker[i])) 133 err(EXIT_FAILURE, "pthread_create"); 134 } 135} 136 137int bench_futex_lock_pi(int argc, const char **argv, 138 const char *prefix __maybe_unused) 139{ 140 int ret = 0; 141 unsigned int i; 142 struct sigaction act; 143 pthread_attr_t thread_attr; 144 145 argc = parse_options(argc, argv, options, bench_futex_lock_pi_usage, 0); 146 if (argc) 147 goto err; 148 149 ncpus = sysconf(_SC_NPROCESSORS_ONLN); 150 151 sigfillset(&act.sa_mask); 152 act.sa_sigaction = toggle_done; 153 sigaction(SIGINT, &act, NULL); 154 155 if (!nthreads) 156 nthreads = ncpus; 157 158 worker = calloc(nthreads, sizeof(*worker)); 159 if (!worker) 160 err(EXIT_FAILURE, "calloc"); 161 162 if (!fshared) 163 futex_flag = FUTEX_PRIVATE_FLAG; 164 165 printf("Run summary [PID %d]: %d threads doing pi lock/unlock pairing for %d secs.\n\n", 166 getpid(), nthreads, nsecs); 167 168 init_stats(&throughput_stats); 169 pthread_mutex_init(&thread_lock, NULL); 170 pthread_cond_init(&thread_parent, NULL); 171 pthread_cond_init(&thread_worker, NULL); 172 173 threads_starting = nthreads; 174 pthread_attr_init(&thread_attr); 175 gettimeofday(&start, NULL); 176 177 create_threads(worker, thread_attr); 178 pthread_attr_destroy(&thread_attr); 179 180 pthread_mutex_lock(&thread_lock); 181 while (threads_starting) 182 pthread_cond_wait(&thread_parent, &thread_lock); 183 pthread_cond_broadcast(&thread_worker); 184 pthread_mutex_unlock(&thread_lock); 185 186 sleep(nsecs); 187 toggle_done(0, NULL, NULL); 188 189 for (i = 0; i < nthreads; i++) { 190 ret = pthread_join(worker[i].thread, NULL); 191 if (ret) 192 err(EXIT_FAILURE, "pthread_join"); 193 } 194 195 /* cleanup & report results */ 196 pthread_cond_destroy(&thread_parent); 197 pthread_cond_destroy(&thread_worker); 198 pthread_mutex_destroy(&thread_lock); 199 200 for (i = 0; i < nthreads; i++) { 201 unsigned long t = worker[i].ops/runtime.tv_sec; 202 203 update_stats(&throughput_stats, t); 204 if (!silent) 205 printf("[thread %3d] futex: %p [ %ld ops/sec ]\n", 206 worker[i].tid, worker[i].futex, t); 207 208 if (multi) 209 free(worker[i].futex); 210 } 211 212 print_summary(); 213 214 free(worker); 215 return ret; 216err: 217 usage_with_options(bench_futex_lock_pi_usage, options); 218 exit(EXIT_FAILURE); 219}