summaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/bpf/benchs/bench_strncmp.c
blob: a5e1428fd7a0c8c4e3f44c83567fc9a5a53a4496 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2021. Huawei Technologies Co., Ltd */
#include <argp.h>
#include "bench.h"
#include "strncmp_bench.skel.h"

static struct strncmp_ctx {
	struct strncmp_bench *skel;
} ctx;

static struct strncmp_args {
	u32 cmp_str_len;
} args = {
	.cmp_str_len = 32,
};

enum {
	ARG_CMP_STR_LEN = 5000,
};

static const struct argp_option opts[] = {
	{ "cmp-str-len", ARG_CMP_STR_LEN, "CMP_STR_LEN", 0,
	  "Set the length of compared string" },
	{},
};

static error_t strncmp_parse_arg(int key, char *arg, struct argp_state *state)
{
	switch (key) {
	case ARG_CMP_STR_LEN:
		args.cmp_str_len = strtoul(arg, NULL, 10);
		if (!args.cmp_str_len ||
		    args.cmp_str_len >= sizeof(ctx.skel->bss->str)) {
			fprintf(stderr, "Invalid cmp str len (limit %zu)\n",
				sizeof(ctx.skel->bss->str));
			argp_usage(state);
		}
		break;
	default:
		return ARGP_ERR_UNKNOWN;
	}

	return 0;
}

const struct argp bench_strncmp_argp = {
	.options = opts,
	.parser = strncmp_parse_arg,
};

static void strncmp_validate(void)
{
	if (env.consumer_cnt != 0) {
		fprintf(stderr, "strncmp benchmark doesn't support consumer!\n");
		exit(1);
	}
}

static void strncmp_setup(void)
{
	int err;
	char *target;
	size_t i, sz;

	sz = sizeof(ctx.skel->rodata->target);
	if (!sz || sz < sizeof(ctx.skel->bss->str)) {
		fprintf(stderr, "invalid string size (target %zu, src %zu)\n",
			sz, sizeof(ctx.skel->bss->str));
		exit(1);
	}

	setup_libbpf();

	ctx.skel = strncmp_bench__open();
	if (!ctx.skel) {
		fprintf(stderr, "failed to open skeleton\n");
		exit(1);
	}

	srandom(time(NULL));
	target = ctx.skel->rodata->target;
	for (i = 0; i < sz - 1; i++)
		target[i] = '1' + random() % 9;
	target[sz - 1] = '\0';

	ctx.skel->rodata->cmp_str_len = args.cmp_str_len;

	memcpy(ctx.skel->bss->str, target, args.cmp_str_len);
	ctx.skel->bss->str[args.cmp_str_len] = '\0';
	/* Make bss->str < rodata->target */
	ctx.skel->bss->str[args.cmp_str_len - 1] -= 1;

	err = strncmp_bench__load(ctx.skel);
	if (err) {
		fprintf(stderr, "failed to load skeleton\n");
		strncmp_bench__destroy(ctx.skel);
		exit(1);
	}
}

static void strncmp_attach_prog(struct bpf_program *prog)
{
	struct bpf_link *link;

	link = bpf_program__attach(prog);
	if (!link) {
		fprintf(stderr, "failed to attach program!\n");
		exit(1);
	}
}

static void strncmp_no_helper_setup(void)
{
	strncmp_setup();
	strncmp_attach_prog(ctx.skel->progs.strncmp_no_helper);
}

static void strncmp_helper_setup(void)
{
	strncmp_setup();
	strncmp_attach_prog(ctx.skel->progs.strncmp_helper);
}

static void *strncmp_producer(void *ctx)
{
	while (true)
		(void)syscall(__NR_getpgid);
	return NULL;
}

static void strncmp_measure(struct bench_res *res)
{
	res->hits = atomic_swap(&ctx.skel->bss->hits, 0);
}

const struct bench bench_strncmp_no_helper = {
	.name = "strncmp-no-helper",
	.argp = &bench_strncmp_argp,
	.validate = strncmp_validate,
	.setup = strncmp_no_helper_setup,
	.producer_thread = strncmp_producer,
	.measure = strncmp_measure,
	.report_progress = hits_drops_report_progress,
	.report_final = hits_drops_report_final,
};

const struct bench bench_strncmp_helper = {
	.name = "strncmp-helper",
	.argp = &bench_strncmp_argp,
	.validate = strncmp_validate,
	.setup = strncmp_helper_setup,
	.producer_thread = strncmp_producer,
	.measure = strncmp_measure,
	.report_progress = hits_drops_report_progress,
	.report_final = hits_drops_report_final,
};