162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * sched-pipe.c 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * pipe: Benchmark for pipe() 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> 962306a36Sopenharmony_ci * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c 1062306a36Sopenharmony_ci * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci#include <subcmd/parse-options.h> 1362306a36Sopenharmony_ci#include "bench.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <unistd.h> 1662306a36Sopenharmony_ci#include <stdio.h> 1762306a36Sopenharmony_ci#include <stdlib.h> 1862306a36Sopenharmony_ci#include <signal.h> 1962306a36Sopenharmony_ci#include <sys/wait.h> 2062306a36Sopenharmony_ci#include <string.h> 2162306a36Sopenharmony_ci#include <errno.h> 2262306a36Sopenharmony_ci#include <assert.h> 2362306a36Sopenharmony_ci#include <sys/time.h> 2462306a36Sopenharmony_ci#include <sys/types.h> 2562306a36Sopenharmony_ci#include <sys/syscall.h> 2662306a36Sopenharmony_ci#include <linux/time64.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <pthread.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistruct thread_data { 3162306a36Sopenharmony_ci int nr; 3262306a36Sopenharmony_ci int pipe_read; 3362306a36Sopenharmony_ci int pipe_write; 3462306a36Sopenharmony_ci pthread_t pthread; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define LOOPS_DEFAULT 1000000 3862306a36Sopenharmony_cistatic int loops = LOOPS_DEFAULT; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* Use processes by default: */ 4162306a36Sopenharmony_cistatic bool threaded; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic const struct option options[] = { 4462306a36Sopenharmony_ci OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), 4562306a36Sopenharmony_ci OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"), 4662306a36Sopenharmony_ci OPT_END() 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic const char * const bench_sched_pipe_usage[] = { 5062306a36Sopenharmony_ci "perf bench sched pipe <options>", 5162306a36Sopenharmony_ci NULL 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void *worker_thread(void *__tdata) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct thread_data *td = __tdata; 5762306a36Sopenharmony_ci int m = 0, i; 5862306a36Sopenharmony_ci int ret; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci for (i = 0; i < loops; i++) { 6162306a36Sopenharmony_ci if (!td->nr) { 6262306a36Sopenharmony_ci ret = read(td->pipe_read, &m, sizeof(int)); 6362306a36Sopenharmony_ci BUG_ON(ret != sizeof(int)); 6462306a36Sopenharmony_ci ret = write(td->pipe_write, &m, sizeof(int)); 6562306a36Sopenharmony_ci BUG_ON(ret != sizeof(int)); 6662306a36Sopenharmony_ci } else { 6762306a36Sopenharmony_ci ret = write(td->pipe_write, &m, sizeof(int)); 6862306a36Sopenharmony_ci BUG_ON(ret != sizeof(int)); 6962306a36Sopenharmony_ci ret = read(td->pipe_read, &m, sizeof(int)); 7062306a36Sopenharmony_ci BUG_ON(ret != sizeof(int)); 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return NULL; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciint bench_sched_pipe(int argc, const char **argv) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci struct thread_data threads[2], *td; 8062306a36Sopenharmony_ci int pipe_1[2], pipe_2[2]; 8162306a36Sopenharmony_ci struct timeval start, stop, diff; 8262306a36Sopenharmony_ci unsigned long long result_usec = 0; 8362306a36Sopenharmony_ci int nr_threads = 2; 8462306a36Sopenharmony_ci int t; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * why does "ret" exist? 8862306a36Sopenharmony_ci * discarding returned value of read(), write() 8962306a36Sopenharmony_ci * causes error in building environment for perf 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci int __maybe_unused ret, wait_stat; 9262306a36Sopenharmony_ci pid_t pid, retpid __maybe_unused; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci BUG_ON(pipe(pipe_1)); 9762306a36Sopenharmony_ci BUG_ON(pipe(pipe_2)); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci gettimeofday(&start, NULL); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (t = 0; t < nr_threads; t++) { 10262306a36Sopenharmony_ci td = threads + t; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci td->nr = t; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (t == 0) { 10762306a36Sopenharmony_ci td->pipe_read = pipe_1[0]; 10862306a36Sopenharmony_ci td->pipe_write = pipe_2[1]; 10962306a36Sopenharmony_ci } else { 11062306a36Sopenharmony_ci td->pipe_write = pipe_1[1]; 11162306a36Sopenharmony_ci td->pipe_read = pipe_2[0]; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (threaded) { 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci for (t = 0; t < nr_threads; t++) { 11962306a36Sopenharmony_ci td = threads + t; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ret = pthread_create(&td->pthread, NULL, worker_thread, td); 12262306a36Sopenharmony_ci BUG_ON(ret); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci for (t = 0; t < nr_threads; t++) { 12662306a36Sopenharmony_ci td = threads + t; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci ret = pthread_join(td->pthread, NULL); 12962306a36Sopenharmony_ci BUG_ON(ret); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci } else { 13362306a36Sopenharmony_ci pid = fork(); 13462306a36Sopenharmony_ci assert(pid >= 0); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (!pid) { 13762306a36Sopenharmony_ci worker_thread(threads + 0); 13862306a36Sopenharmony_ci exit(0); 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci worker_thread(threads + 1); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci retpid = waitpid(pid, &wait_stat, 0); 14462306a36Sopenharmony_ci assert((retpid == pid) && WIFEXITED(wait_stat)); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci gettimeofday(&stop, NULL); 14862306a36Sopenharmony_ci timersub(&stop, &start, &diff); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci switch (bench_format) { 15162306a36Sopenharmony_ci case BENCH_FORMAT_DEFAULT: 15262306a36Sopenharmony_ci printf("# Executed %d pipe operations between two %s\n\n", 15362306a36Sopenharmony_ci loops, threaded ? "threads" : "processes"); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci result_usec = diff.tv_sec * USEC_PER_SEC; 15662306a36Sopenharmony_ci result_usec += diff.tv_usec; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", 15962306a36Sopenharmony_ci (unsigned long) diff.tv_sec, 16062306a36Sopenharmony_ci (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci printf(" %14lf usecs/op\n", 16362306a36Sopenharmony_ci (double)result_usec / (double)loops); 16462306a36Sopenharmony_ci printf(" %14d ops/sec\n", 16562306a36Sopenharmony_ci (int)((double)loops / 16662306a36Sopenharmony_ci ((double)result_usec / (double)USEC_PER_SEC))); 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci case BENCH_FORMAT_SIMPLE: 17062306a36Sopenharmony_ci printf("%lu.%03lu\n", 17162306a36Sopenharmony_ci (unsigned long) diff.tv_sec, 17262306a36Sopenharmony_ci (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci default: 17662306a36Sopenharmony_ci /* reaching here is something disaster */ 17762306a36Sopenharmony_ci fprintf(stderr, "Unknown format:%d\n", bench_format); 17862306a36Sopenharmony_ci exit(1); 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 184