brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 0b90275 Raw
214 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/*3 * uprobe.c4 *5 * uprobe benchmarks6 *7 *  Copyright (C) 2023, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>8 */9#include "../perf.h"10#include "../util/util.h"11#include <subcmd/parse-options.h>12#include "../builtin.h"13#include "bench.h"14#include <linux/compiler.h>15#include <linux/time64.h>16 17#include <inttypes.h>18#include <stdio.h>19#include <sys/time.h>20#include <sys/types.h>21#include <time.h>22#include <unistd.h>23#include <stdlib.h>24 25#define LOOPS_DEFAULT 100026static int loops = LOOPS_DEFAULT;27 28enum bench_uprobe {29	BENCH_UPROBE__BASELINE,30	BENCH_UPROBE__EMPTY,31	BENCH_UPROBE__TRACE_PRINTK,32	BENCH_UPROBE__EMPTY_RET,33	BENCH_UPROBE__TRACE_PRINTK_RET,34};35 36static const struct option options[] = {37	OPT_INTEGER('l', "loop",	&loops,		"Specify number of loops"),38	OPT_END()39};40 41static const char * const bench_uprobe_usage[] = {42	"perf bench uprobe <options>",43	NULL44};45 46#ifdef HAVE_BPF_SKEL47#include "bpf_skel/bench_uprobe.skel.h"48 49#define bench_uprobe__attach_uprobe(prog) \50	skel->links.prog = bpf_program__attach_uprobe_opts(/*prog=*/skel->progs.prog, \51							   /*pid=*/-1, \52							   /*binary_path=*/"libc.so.6", \53							   /*func_offset=*/0, \54							   /*opts=*/&uprobe_opts); \55	if (!skel->links.prog) { \56		err = -errno; \57		fprintf(stderr, "Failed to attach bench uprobe \"%s\": %s\n", #prog, strerror(errno)); \58		goto cleanup; \59	}60 61struct bench_uprobe_bpf *skel;62 63static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench)64{65	DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);66	int err;67 68	/* Load and verify BPF application */69	skel = bench_uprobe_bpf__open();70	if (!skel) {71		fprintf(stderr, "Failed to open and load uprobes bench BPF skeleton\n");72		return -1;73	}74 75	err = bench_uprobe_bpf__load(skel);76	if (err) {77		fprintf(stderr, "Failed to load and verify BPF skeleton\n");78		goto cleanup;79	}80 81	uprobe_opts.func_name = "usleep";82	switch (bench) {83	case BENCH_UPROBE__BASELINE:							break;84	case BENCH_UPROBE__EMPTY:	 bench_uprobe__attach_uprobe(empty);		break;85	case BENCH_UPROBE__TRACE_PRINTK: bench_uprobe__attach_uprobe(trace_printk);	break;86	case BENCH_UPROBE__EMPTY_RET:	 bench_uprobe__attach_uprobe(empty_ret);	break;87	case BENCH_UPROBE__TRACE_PRINTK_RET: bench_uprobe__attach_uprobe(trace_printk_ret); break;88	default:89		fprintf(stderr, "Invalid bench: %d\n", bench);90		goto cleanup;91	}92 93	return err;94cleanup:95	bench_uprobe_bpf__destroy(skel);96	skel = NULL;97	return err;98}99 100static void bench_uprobe__teardown_bpf_skel(void)101{102	if (skel) {103		bench_uprobe_bpf__destroy(skel);104		skel = NULL;105	}106}107#else108static int bench_uprobe__setup_bpf_skel(enum bench_uprobe bench __maybe_unused) { return 0; }109static void bench_uprobe__teardown_bpf_skel(void) {};110#endif111 112static int bench_uprobe_format__default_fprintf(const char *name, const char *unit, u64 diff, FILE *fp)113{114	static u64 baseline, previous;115	s64 diff_to_baseline = diff - baseline,116	    diff_to_previous = diff - previous;117	int printed = fprintf(fp, "# Executed %'d %s calls\n", loops, name);118 119	printed += fprintf(fp, " %14s: %'" PRIu64 " %ss", "Total time", diff, unit);120 121	if (baseline) {122		printed += fprintf(fp, " %s%'" PRId64 " to baseline", diff_to_baseline > 0 ? "+" : "", diff_to_baseline);123 124		if (previous != baseline)125			fprintf(stdout, " %s%'" PRId64 " to previous", diff_to_previous > 0 ? "+" : "", diff_to_previous);126	}127 128	printed += fprintf(fp, "\n\n %'.3f %ss/op", (double)diff / (double)loops, unit);129 130	if (baseline) {131		printed += fprintf(fp, " %'.3f %ss/op to baseline", (double)diff_to_baseline / (double)loops, unit);132 133		if (previous != baseline)134			printed += fprintf(fp, " %'.3f %ss/op to previous", (double)diff_to_previous / (double)loops, unit);135	} else {136		baseline = diff;137	}138 139	fputc('\n', fp);140 141	previous = diff;142 143	return printed + 1;144}145 146static int bench_uprobe(int argc, const char **argv, enum bench_uprobe bench)147{148	const char *name = "usleep(1000)", *unit = "usec";149	struct timespec start, end;150	u64 diff;151	int i;152 153	argc = parse_options(argc, argv, options, bench_uprobe_usage, 0);154 155	if (bench != BENCH_UPROBE__BASELINE && bench_uprobe__setup_bpf_skel(bench) < 0)156		return 0;157 158        clock_gettime(CLOCK_REALTIME, &start);159 160	for (i = 0; i < loops; i++) {161		usleep(USEC_PER_MSEC);162	}163 164	clock_gettime(CLOCK_REALTIME, &end);165 166	diff = end.tv_sec * NSEC_PER_SEC + end.tv_nsec - (start.tv_sec * NSEC_PER_SEC + start.tv_nsec);167	diff /= NSEC_PER_USEC;168 169	switch (bench_format) {170	case BENCH_FORMAT_DEFAULT:171		bench_uprobe_format__default_fprintf(name, unit, diff, stdout);172		break;173 174	case BENCH_FORMAT_SIMPLE:175		printf("%" PRIu64 "\n", diff);176		break;177 178	default:179		/* reaching here is something of a disaster */180		fprintf(stderr, "Unknown format:%d\n", bench_format);181		exit(1);182	}183 184	if (bench != BENCH_UPROBE__BASELINE)185		bench_uprobe__teardown_bpf_skel();186 187	return 0;188}189 190int bench_uprobe_baseline(int argc, const char **argv)191{192	return bench_uprobe(argc, argv, BENCH_UPROBE__BASELINE);193}194 195int bench_uprobe_empty(int argc, const char **argv)196{197	return bench_uprobe(argc, argv, BENCH_UPROBE__EMPTY);198}199 200int bench_uprobe_trace_printk(int argc, const char **argv)201{202	return bench_uprobe(argc, argv, BENCH_UPROBE__TRACE_PRINTK);203}204 205int bench_uprobe_empty_ret(int argc, const char **argv)206{207	return bench_uprobe(argc, argv, BENCH_UPROBE__EMPTY_RET);208}209 210int bench_uprobe_trace_printk_ret(int argc, const char **argv)211{212	return bench_uprobe(argc, argv, BENCH_UPROBE__TRACE_PRINTK_RET);213}214