^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * sched-pipe.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * pipe: Benchmark for pipe()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <subcmd/parse-options.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "bench.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sys/wait.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <assert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <sys/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <sys/syscall.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/time64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <pthread.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct thread_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) int pipe_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) int pipe_write;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) pthread_t pthread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define LOOPS_DEFAULT 1000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static int loops = LOOPS_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /* Use processes by default: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static bool threaded;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static const struct option options[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) OPT_INTEGER('l', "loop", &loops, "Specify number of loops"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) OPT_END()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static const char * const bench_sched_pipe_usage[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) "perf bench sched pipe <options>",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void *worker_thread(void *__tdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct thread_data *td = __tdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int m = 0, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) for (i = 0; i < loops; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (!td->nr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ret = read(td->pipe_read, &m, sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) BUG_ON(ret != sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ret = write(td->pipe_write, &m, sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) BUG_ON(ret != sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) ret = write(td->pipe_write, &m, sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) BUG_ON(ret != sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ret = read(td->pipe_read, &m, sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) BUG_ON(ret != sizeof(int));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int bench_sched_pipe(int argc, const char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct thread_data threads[2], *td;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) int pipe_1[2], pipe_2[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct timeval start, stop, diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) unsigned long long result_usec = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int nr_threads = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * why does "ret" exist?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * discarding returned value of read(), write()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * causes error in building environment for perf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) int __maybe_unused ret, wait_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pid_t pid, retpid __maybe_unused;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) BUG_ON(pipe(pipe_1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) BUG_ON(pipe(pipe_2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) gettimeofday(&start, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) for (t = 0; t < nr_threads; t++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) td = threads + t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) td->nr = t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (t == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) td->pipe_read = pipe_1[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) td->pipe_write = pipe_2[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) td->pipe_write = pipe_1[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) td->pipe_read = pipe_2[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (threaded) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) for (t = 0; t < nr_threads; t++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) td = threads + t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ret = pthread_create(&td->pthread, NULL, worker_thread, td);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) BUG_ON(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) for (t = 0; t < nr_threads; t++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) td = threads + t;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) ret = pthread_join(td->pthread, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) BUG_ON(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) pid = fork();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) assert(pid >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (!pid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) worker_thread(threads + 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) exit(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) worker_thread(threads + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) retpid = waitpid(pid, &wait_stat, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) assert((retpid == pid) && WIFEXITED(wait_stat));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) gettimeofday(&stop, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) timersub(&stop, &start, &diff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) switch (bench_format) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) case BENCH_FORMAT_DEFAULT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) printf("# Executed %d pipe operations between two %s\n\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) loops, threaded ? "threads" : "processes");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) result_usec = diff.tv_sec * USEC_PER_SEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) result_usec += diff.tv_usec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) diff.tv_sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) printf(" %14lf usecs/op\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) (double)result_usec / (double)loops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) printf(" %14d ops/sec\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) (int)((double)loops /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) ((double)result_usec / (double)USEC_PER_SEC)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) case BENCH_FORMAT_SIMPLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) printf("%lu.%03lu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) diff.tv_sec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) (unsigned long) (diff.tv_usec / USEC_PER_MSEC));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* reaching here is something disaster */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) fprintf(stderr, "Unknown format:%d\n", bench_format);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) exit(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }