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