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