cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sched-pipe.c (3947B)


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