18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * sched-pipe.c 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * pipe: Benchmark for pipe() 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Based on pipe-test-1m.c by Ingo Molnar <mingo@redhat.com> 98c2ecf20Sopenharmony_ci * http://people.redhat.com/mingo/cfs-scheduler/tools/pipe-test-1m.c 108c2ecf20Sopenharmony_ci * Ported to perf by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 138c2ecf20Sopenharmony_ci#include "bench.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <unistd.h> 168c2ecf20Sopenharmony_ci#include <stdio.h> 178c2ecf20Sopenharmony_ci#include <stdlib.h> 188c2ecf20Sopenharmony_ci#include <signal.h> 198c2ecf20Sopenharmony_ci#include <sys/wait.h> 208c2ecf20Sopenharmony_ci#include <string.h> 218c2ecf20Sopenharmony_ci#include <errno.h> 228c2ecf20Sopenharmony_ci#include <assert.h> 238c2ecf20Sopenharmony_ci#include <sys/time.h> 248c2ecf20Sopenharmony_ci#include <sys/types.h> 258c2ecf20Sopenharmony_ci#include <sys/syscall.h> 268c2ecf20Sopenharmony_ci#include <linux/time64.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <pthread.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct thread_data { 318c2ecf20Sopenharmony_ci int nr; 328c2ecf20Sopenharmony_ci int pipe_read; 338c2ecf20Sopenharmony_ci int pipe_write; 348c2ecf20Sopenharmony_ci pthread_t pthread; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define LOOPS_DEFAULT 1000000 388c2ecf20Sopenharmony_cistatic int loops = LOOPS_DEFAULT; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Use processes by default: */ 418c2ecf20Sopenharmony_cistatic bool threaded; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic const struct option options[] = { 448c2ecf20Sopenharmony_ci OPT_INTEGER('l', "loop", &loops, "Specify number of loops"), 458c2ecf20Sopenharmony_ci OPT_BOOLEAN('T', "threaded", &threaded, "Specify threads/process based task setup"), 468c2ecf20Sopenharmony_ci OPT_END() 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic const char * const bench_sched_pipe_usage[] = { 508c2ecf20Sopenharmony_ci "perf bench sched pipe <options>", 518c2ecf20Sopenharmony_ci NULL 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void *worker_thread(void *__tdata) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct thread_data *td = __tdata; 578c2ecf20Sopenharmony_ci int m = 0, i; 588c2ecf20Sopenharmony_ci int ret; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci for (i = 0; i < loops; i++) { 618c2ecf20Sopenharmony_ci if (!td->nr) { 628c2ecf20Sopenharmony_ci ret = read(td->pipe_read, &m, sizeof(int)); 638c2ecf20Sopenharmony_ci BUG_ON(ret != sizeof(int)); 648c2ecf20Sopenharmony_ci ret = write(td->pipe_write, &m, sizeof(int)); 658c2ecf20Sopenharmony_ci BUG_ON(ret != sizeof(int)); 668c2ecf20Sopenharmony_ci } else { 678c2ecf20Sopenharmony_ci ret = write(td->pipe_write, &m, sizeof(int)); 688c2ecf20Sopenharmony_ci BUG_ON(ret != sizeof(int)); 698c2ecf20Sopenharmony_ci ret = read(td->pipe_read, &m, sizeof(int)); 708c2ecf20Sopenharmony_ci BUG_ON(ret != sizeof(int)); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return NULL; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciint bench_sched_pipe(int argc, const char **argv) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct thread_data threads[2], *td; 808c2ecf20Sopenharmony_ci int pipe_1[2], pipe_2[2]; 818c2ecf20Sopenharmony_ci struct timeval start, stop, diff; 828c2ecf20Sopenharmony_ci unsigned long long result_usec = 0; 838c2ecf20Sopenharmony_ci int nr_threads = 2; 848c2ecf20Sopenharmony_ci int t; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * why does "ret" exist? 888c2ecf20Sopenharmony_ci * discarding returned value of read(), write() 898c2ecf20Sopenharmony_ci * causes error in building environment for perf 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci int __maybe_unused ret, wait_stat; 928c2ecf20Sopenharmony_ci pid_t pid, retpid __maybe_unused; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci argc = parse_options(argc, argv, options, bench_sched_pipe_usage, 0); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci BUG_ON(pipe(pipe_1)); 978c2ecf20Sopenharmony_ci BUG_ON(pipe(pipe_2)); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci gettimeofday(&start, NULL); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for (t = 0; t < nr_threads; t++) { 1028c2ecf20Sopenharmony_ci td = threads + t; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci td->nr = t; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (t == 0) { 1078c2ecf20Sopenharmony_ci td->pipe_read = pipe_1[0]; 1088c2ecf20Sopenharmony_ci td->pipe_write = pipe_2[1]; 1098c2ecf20Sopenharmony_ci } else { 1108c2ecf20Sopenharmony_ci td->pipe_write = pipe_1[1]; 1118c2ecf20Sopenharmony_ci td->pipe_read = pipe_2[0]; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (threaded) { 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci for (t = 0; t < nr_threads; t++) { 1198c2ecf20Sopenharmony_ci td = threads + t; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ret = pthread_create(&td->pthread, NULL, worker_thread, td); 1228c2ecf20Sopenharmony_ci BUG_ON(ret); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci for (t = 0; t < nr_threads; t++) { 1268c2ecf20Sopenharmony_ci td = threads + t; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ret = pthread_join(td->pthread, NULL); 1298c2ecf20Sopenharmony_ci BUG_ON(ret); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci pid = fork(); 1348c2ecf20Sopenharmony_ci assert(pid >= 0); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!pid) { 1378c2ecf20Sopenharmony_ci worker_thread(threads + 0); 1388c2ecf20Sopenharmony_ci exit(0); 1398c2ecf20Sopenharmony_ci } else { 1408c2ecf20Sopenharmony_ci worker_thread(threads + 1); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci retpid = waitpid(pid, &wait_stat, 0); 1448c2ecf20Sopenharmony_ci assert((retpid == pid) && WIFEXITED(wait_stat)); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci gettimeofday(&stop, NULL); 1488c2ecf20Sopenharmony_ci timersub(&stop, &start, &diff); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci switch (bench_format) { 1518c2ecf20Sopenharmony_ci case BENCH_FORMAT_DEFAULT: 1528c2ecf20Sopenharmony_ci printf("# Executed %d pipe operations between two %s\n\n", 1538c2ecf20Sopenharmony_ci loops, threaded ? "threads" : "processes"); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci result_usec = diff.tv_sec * USEC_PER_SEC; 1568c2ecf20Sopenharmony_ci result_usec += diff.tv_usec; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci printf(" %14s: %lu.%03lu [sec]\n\n", "Total time", 1598c2ecf20Sopenharmony_ci diff.tv_sec, 1608c2ecf20Sopenharmony_ci (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci printf(" %14lf usecs/op\n", 1638c2ecf20Sopenharmony_ci (double)result_usec / (double)loops); 1648c2ecf20Sopenharmony_ci printf(" %14d ops/sec\n", 1658c2ecf20Sopenharmony_ci (int)((double)loops / 1668c2ecf20Sopenharmony_ci ((double)result_usec / (double)USEC_PER_SEC))); 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci case BENCH_FORMAT_SIMPLE: 1708c2ecf20Sopenharmony_ci printf("%lu.%03lu\n", 1718c2ecf20Sopenharmony_ci diff.tv_sec, 1728c2ecf20Sopenharmony_ci (unsigned long) (diff.tv_usec / USEC_PER_MSEC)); 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci default: 1768c2ecf20Sopenharmony_ci /* reaching here is something disaster */ 1778c2ecf20Sopenharmony_ci fprintf(stderr, "Unknown format:%d\n", bench_format); 1788c2ecf20Sopenharmony_ci exit(1); 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 184