brintos

brintos / linux-shallow public Read only

0
0
Text · 6.0 KiB · 279ff1b Raw
278 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2023 Isovalent */3 4#include <sys/random.h>5#include <argp.h>6#include "bench.h"7#include "bpf_hashmap_lookup.skel.h"8#include "bpf_util.h"9 10/* BPF triggering benchmarks */11static struct ctx {12	struct bpf_hashmap_lookup *skel;13} ctx;14 15/* only available to kernel, so define it here */16#define BPF_MAX_LOOPS (1<<23)17 18#define MAX_KEY_SIZE 1024 /* the size of the key map */19 20static struct {21	__u32 key_size;22	__u32 map_flags;23	__u32 max_entries;24	__u32 nr_entries;25	__u32 nr_loops;26} args = {27	.key_size = 4,28	.map_flags = 0,29	.max_entries = 1000,30	.nr_entries = 500,31	.nr_loops = 1000000,32};33 34enum {35	ARG_KEY_SIZE = 8001,36	ARG_MAP_FLAGS,37	ARG_MAX_ENTRIES,38	ARG_NR_ENTRIES,39	ARG_NR_LOOPS,40};41 42static const struct argp_option opts[] = {43	{ "key_size", ARG_KEY_SIZE, "KEY_SIZE", 0,44	  "The hashmap key size (max 1024)"},45	{ "map_flags", ARG_MAP_FLAGS, "MAP_FLAGS", 0,46	  "The hashmap flags passed to BPF_MAP_CREATE"},47	{ "max_entries", ARG_MAX_ENTRIES, "MAX_ENTRIES", 0,48	  "The hashmap max entries"},49	{ "nr_entries", ARG_NR_ENTRIES, "NR_ENTRIES", 0,50	  "The number of entries to insert/lookup"},51	{ "nr_loops", ARG_NR_LOOPS, "NR_LOOPS", 0,52	  "The number of loops for the benchmark"},53	{},54};55 56static error_t parse_arg(int key, char *arg, struct argp_state *state)57{58	long ret;59 60	switch (key) {61	case ARG_KEY_SIZE:62		ret = strtol(arg, NULL, 10);63		if (ret < 1 || ret > MAX_KEY_SIZE) {64			fprintf(stderr, "invalid key_size");65			argp_usage(state);66		}67		args.key_size = ret;68		break;69	case ARG_MAP_FLAGS:70		ret = strtol(arg, NULL, 0);71		if (ret < 0 || ret > UINT_MAX) {72			fprintf(stderr, "invalid map_flags");73			argp_usage(state);74		}75		args.map_flags = ret;76		break;77	case ARG_MAX_ENTRIES:78		ret = strtol(arg, NULL, 10);79		if (ret < 1 || ret > UINT_MAX) {80			fprintf(stderr, "invalid max_entries");81			argp_usage(state);82		}83		args.max_entries = ret;84		break;85	case ARG_NR_ENTRIES:86		ret = strtol(arg, NULL, 10);87		if (ret < 1 || ret > UINT_MAX) {88			fprintf(stderr, "invalid nr_entries");89			argp_usage(state);90		}91		args.nr_entries = ret;92		break;93	case ARG_NR_LOOPS:94		ret = strtol(arg, NULL, 10);95		if (ret < 1 || ret > BPF_MAX_LOOPS) {96			fprintf(stderr, "invalid nr_loops: %ld (min=1 max=%u)\n",97				ret, BPF_MAX_LOOPS);98			argp_usage(state);99		}100		args.nr_loops = ret;101		break;102	default:103		return ARGP_ERR_UNKNOWN;104	}105 106	return 0;107}108 109const struct argp bench_hashmap_lookup_argp = {110	.options = opts,111	.parser = parse_arg,112};113 114static void validate(void)115{116	if (env.consumer_cnt != 0) {117		fprintf(stderr, "benchmark doesn't support consumer!\n");118		exit(1);119	}120 121	if (args.nr_entries > args.max_entries) {122		fprintf(stderr, "args.nr_entries is too big! (max %u, got %u)\n",123			args.max_entries, args.nr_entries);124		exit(1);125	}126}127 128static void *producer(void *input)129{130	while (true) {131		/* trigger the bpf program */132		syscall(__NR_getpgid);133	}134	return NULL;135}136 137static void measure(struct bench_res *res)138{139}140 141static inline void patch_key(u32 i, u32 *key)142{143#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__144	*key = i + 1;145#else146	*key = __builtin_bswap32(i + 1);147#endif148	/* the rest of key is random */149}150 151static void setup(void)152{153	struct bpf_link *link;154	int map_fd;155	int ret;156	int i;157 158	setup_libbpf();159 160	ctx.skel = bpf_hashmap_lookup__open();161	if (!ctx.skel) {162		fprintf(stderr, "failed to open skeleton\n");163		exit(1);164	}165 166	bpf_map__set_max_entries(ctx.skel->maps.hash_map_bench, args.max_entries);167	bpf_map__set_key_size(ctx.skel->maps.hash_map_bench, args.key_size);168	bpf_map__set_value_size(ctx.skel->maps.hash_map_bench, 8);169	bpf_map__set_map_flags(ctx.skel->maps.hash_map_bench, args.map_flags);170 171	ctx.skel->bss->nr_entries = args.nr_entries;172	ctx.skel->bss->nr_loops = args.nr_loops / args.nr_entries;173 174	if (args.key_size > 4) {175		for (i = 1; i < args.key_size/4; i++)176			ctx.skel->bss->key[i] = 2654435761 * i;177	}178 179	ret = bpf_hashmap_lookup__load(ctx.skel);180	if (ret) {181		bpf_hashmap_lookup__destroy(ctx.skel);182		fprintf(stderr, "failed to load map: %s", strerror(-ret));183		exit(1);184	}185 186	/* fill in the hash_map */187	map_fd = bpf_map__fd(ctx.skel->maps.hash_map_bench);188	for (u64 i = 0; i < args.nr_entries; i++) {189		patch_key(i, ctx.skel->bss->key);190		bpf_map_update_elem(map_fd, ctx.skel->bss->key, &i, BPF_ANY);191	}192 193	link = bpf_program__attach(ctx.skel->progs.benchmark);194	if (!link) {195		fprintf(stderr, "failed to attach program!\n");196		exit(1);197	}198}199 200static inline double events_from_time(u64 time)201{202	if (time)203		return args.nr_loops * 1000000000llu / time / 1000000.0L;204 205	return 0;206}207 208static int compute_events(u64 *times, double *events_mean, double *events_stddev, u64 *mean_time)209{210	int i, n = 0;211 212	*events_mean = 0;213	*events_stddev = 0;214	*mean_time = 0;215 216	for (i = 0; i < 32; i++) {217		if (!times[i])218			break;219		*mean_time += times[i];220		*events_mean += events_from_time(times[i]);221		n += 1;222	}223	if (!n)224		return 0;225 226	*mean_time /= n;227	*events_mean /= n;228 229	if (n > 1) {230		for (i = 0; i < n; i++) {231			double events_i = *events_mean - events_from_time(times[i]);232			*events_stddev += events_i * events_i / (n - 1);233		}234		*events_stddev = sqrt(*events_stddev);235	}236 237	return n;238}239 240static void hashmap_report_final(struct bench_res res[], int res_cnt)241{242	unsigned int nr_cpus = bpf_num_possible_cpus();243	double events_mean, events_stddev;244	u64 mean_time;245	int i, n;246 247	for (i = 0; i < nr_cpus; i++) {248		n = compute_events(ctx.skel->bss->percpu_times[i], &events_mean,249				   &events_stddev, &mean_time);250		if (n == 0)251			continue;252 253		if (env.quiet) {254			/* we expect only one cpu to be present */255			if (env.affinity)256				printf("%.3lf\n", events_mean);257			else258				printf("cpu%02d %.3lf\n", i, events_mean);259		} else {260			printf("cpu%02d: lookup %.3lfM ± %.3lfM events/sec"261			       " (approximated from %d samples of ~%lums)\n",262			       i, events_mean, 2*events_stddev,263			       n, mean_time / 1000000);264		}265	}266}267 268const struct bench bench_bpf_hashmap_lookup = {269	.name = "bpf-hashmap-lookup",270	.argp = &bench_hashmap_lookup_argp,271	.validate = validate,272	.setup = setup,273	.producer_thread = producer,274	.measure = measure,275	.report_progress = NULL,276	.report_final = hashmap_report_final,277};278