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

perf bench sched: Add --threaded option

Allow the measurement of thread versus process context switch
performance.

The default stays at 'process' based measurement, like lmbench's lat_ctx
benchmark.

Sample output:

comet:~/tip/tools/perf> taskset 1 ./perf bench sched pipe
# Running sched/pipe benchmark...
# Executed 1000000 pipe operations between two processes

Total time: 4.138 [sec]

4.138729 usecs/op
241620 ops/sec
comet:~/tip/tools/perf> taskset 1 ./perf bench sched pipe --threaded
# Running sched/pipe benchmark...
# Executed 1000000 pipe operations between two threads

Total time: 3.667 [sec]

3.667667 usecs/op
272652 ops/sec

Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Link: http://lkml.kernel.org/r/20130917114256.GA31159@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ingo Molnar and committed by
Arnaldo Carvalho de Melo
a9faa0ca b52bc234

+86 -29
+86 -29
tools/perf/bench/sched-pipe.c
··· 7 7 * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> 8 8 * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c 9 9 * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 10 - * 11 10 */ 12 - 13 11 #include "../perf.h" 14 12 #include "../util/util.h" 15 13 #include "../util/parse-options.h" ··· 26 28 #include <sys/time.h> 27 29 #include <sys/types.h> 28 30 31 + #include <pthread.h> 32 + 33 + struct thread_data { 34 + int nr; 35 + int pipe_read; 36 + int pipe_write; 37 + pthread_t pthread; 38 + }; 39 + 29 40 #define LOOPS_DEFAULT 1000000 30 - static int loops = LOOPS_DEFAULT; 41 + static int loops = LOOPS_DEFAULT; 42 + 43 + /* Use processes by default: */ 44 + static bool threaded; 31 45 32 46 static const struct option options[] = { 33 - OPT_INTEGER('l', "loop", &loops, 34 - "Specify number of loops"), 47 + OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), 48 + OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"), 35 49 OPT_END() 36 50 }; 37 51 ··· 52 42 NULL 53 43 }; 54 44 55 - int bench_sched_pipe(int argc, const char **argv, 56 - const char *prefix __maybe_unused) 45 + static void *worker_thread(void *__tdata) 57 46 { 58 - int pipe_1[2], pipe_2[2]; 47 + struct thread_data *td = __tdata; 59 48 int m = 0, i; 49 + int ret; 50 + 51 + for (i = 0; i < loops; i++) { 52 + if (!td->nr) { 53 + ret = read(td->pipe_read, &m, sizeof(int)); 54 + BUG_ON(ret != sizeof(int)); 55 + ret = write(td->pipe_write, &m, sizeof(int)); 56 + BUG_ON(ret != sizeof(int)); 57 + } else { 58 + ret = write(td->pipe_write, &m, sizeof(int)); 59 + BUG_ON(ret != sizeof(int)); 60 + ret = read(td->pipe_read, &m, sizeof(int)); 61 + BUG_ON(ret != sizeof(int)); 62 + } 63 + } 64 + 65 + return NULL; 66 + } 67 + 68 + int bench_sched_pipe(int argc, const char **argv, const char *prefix __maybe_unused) 69 + { 70 + struct thread_data threads[2], *td; 71 + int pipe_1[2], pipe_2[2]; 60 72 struct timeval start, stop, diff; 61 73 unsigned long long result_usec = 0; 74 + int nr_threads = 2; 75 + int t; 62 76 63 77 /* 64 78 * why does "ret" exist? ··· 92 58 int __maybe_unused ret, wait_stat; 93 59 pid_t pid, retpid __maybe_unused; 94 60 95 - argc = parse_options(argc, argv, options, 96 - bench_sched_pipe_usage, 0); 61 + argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0); 97 62 98 63 BUG_ON(pipe(pipe_1)); 99 64 BUG_ON(pipe(pipe_2)); 100 65 101 - pid = fork(); 102 - assert(pid >= 0); 103 - 104 66 gettimeofday(&start, NULL); 105 67 106 - if (!pid) { 107 - for (i = 0; i < loops; i++) { 108 - ret = read(pipe_1[0], &m, sizeof(int)); 109 - ret = write(pipe_2[1], &m, sizeof(int)); 68 + for (t = 0; t < nr_threads; t++) { 69 + td = threads + t; 70 + 71 + td->nr = t; 72 + 73 + if (t == 0) { 74 + td->pipe_read = pipe_1[0]; 75 + td->pipe_write = pipe_2[1]; 76 + } else { 77 + td->pipe_write = pipe_1[1]; 78 + td->pipe_read = pipe_2[0]; 110 79 } 80 + } 81 + 82 + 83 + if (threaded) { 84 + 85 + for (t = 0; t < nr_threads; t++) { 86 + td = threads + t; 87 + 88 + ret = pthread_create(&td->pthread, NULL, worker_thread, td); 89 + BUG_ON(ret); 90 + } 91 + 92 + for (t = 0; t < nr_threads; t++) { 93 + td = threads + t; 94 + 95 + ret = pthread_join(td->pthread, NULL); 96 + BUG_ON(ret); 97 + } 98 + 111 99 } else { 112 - for (i = 0; i < loops; i++) { 113 - ret = write(pipe_1[1], &m, sizeof(int)); 114 - ret = read(pipe_2[0], &m, sizeof(int)); 100 + pid = fork(); 101 + assert(pid >= 0); 102 + 103 + if (!pid) { 104 + worker_thread(threads + 0); 105 + exit(0); 106 + } else { 107 + worker_thread(threads + 1); 115 108 } 109 + 110 + retpid = waitpid(pid, &wait_stat, 0); 111 + assert((retpid == pid) && WIFEXITED(wait_stat)); 116 112 } 117 113 118 114 gettimeofday(&stop, NULL); 119 115 timersub(&stop, &start, &diff); 120 116 121 - if (pid) { 122 - retpid = waitpid(pid, &wait_stat, 0); 123 - assert((retpid == pid) && WIFEXITED(wait_stat)); 124 - } else { 125 - exit(0); 126 - } 127 - 128 117 switch (bench_format) { 129 118 case BENCH_FORMAT_DEFAULT: 130 - printf("# Executed %d pipe operations between two tasks\n\n", 131 - loops); 119 + printf("# Executed %d pipe operations between two %s\n\n", 120 + loops, threaded ? "threads" : "processes"); 132 121 133 122 result_usec = diff.tv_sec * 1000000; 134 123 result_usec += diff.tv_usec;