1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2021. Huawei Technologies Co., Ltd */
3 #include <argp.h>
4 #include "bench.h"
5 #include "strncmp_bench.skel.h"
6 
7 static struct strncmp_ctx {
8 	struct strncmp_bench *skel;
9 } ctx;
10 
11 static struct strncmp_args {
12 	u32 cmp_str_len;
13 } args = {
14 	.cmp_str_len = 32,
15 };
16 
17 enum {
18 	ARG_CMP_STR_LEN = 5000,
19 };
20 
21 static const struct argp_option opts[] = {
22 	{ "cmp-str-len", ARG_CMP_STR_LEN, "CMP_STR_LEN", 0,
23 	  "Set the length of compared string" },
24 	{},
25 };
26 
27 static error_t strncmp_parse_arg(int key, char *arg, struct argp_state *state)
28 {
29 	switch (key) {
30 	case ARG_CMP_STR_LEN:
31 		args.cmp_str_len = strtoul(arg, NULL, 10);
32 		if (!args.cmp_str_len ||
33 		    args.cmp_str_len >= sizeof(ctx.skel->bss->str)) {
34 			fprintf(stderr, "Invalid cmp str len (limit %zu)\n",
35 				sizeof(ctx.skel->bss->str));
36 			argp_usage(state);
37 		}
38 		break;
39 	default:
40 		return ARGP_ERR_UNKNOWN;
41 	}
42 
43 	return 0;
44 }
45 
46 const struct argp bench_strncmp_argp = {
47 	.options = opts,
48 	.parser = strncmp_parse_arg,
49 };
50 
51 static void strncmp_validate(void)
52 {
53 	if (env.consumer_cnt != 1) {
54 		fprintf(stderr, "strncmp benchmark doesn't support multi-consumer!\n");
55 		exit(1);
56 	}
57 }
58 
59 static void strncmp_setup(void)
60 {
61 	int err;
62 	char *target;
63 	size_t i, sz;
64 
65 	sz = sizeof(ctx.skel->rodata->target);
66 	if (!sz || sz < sizeof(ctx.skel->bss->str)) {
67 		fprintf(stderr, "invalid string size (target %zu, src %zu)\n",
68 			sz, sizeof(ctx.skel->bss->str));
69 		exit(1);
70 	}
71 
72 	setup_libbpf();
73 
74 	ctx.skel = strncmp_bench__open();
75 	if (!ctx.skel) {
76 		fprintf(stderr, "failed to open skeleton\n");
77 		exit(1);
78 	}
79 
80 	srandom(time(NULL));
81 	target = ctx.skel->rodata->target;
82 	for (i = 0; i < sz - 1; i++)
83 		target[i] = '1' + random() % 9;
84 	target[sz - 1] = '\0';
85 
86 	ctx.skel->rodata->cmp_str_len = args.cmp_str_len;
87 
88 	memcpy(ctx.skel->bss->str, target, args.cmp_str_len);
89 	ctx.skel->bss->str[args.cmp_str_len] = '\0';
90 	/* Make bss->str < rodata->target */
91 	ctx.skel->bss->str[args.cmp_str_len - 1] -= 1;
92 
93 	err = strncmp_bench__load(ctx.skel);
94 	if (err) {
95 		fprintf(stderr, "failed to load skeleton\n");
96 		strncmp_bench__destroy(ctx.skel);
97 		exit(1);
98 	}
99 }
100 
101 static void strncmp_attach_prog(struct bpf_program *prog)
102 {
103 	struct bpf_link *link;
104 
105 	link = bpf_program__attach(prog);
106 	if (!link) {
107 		fprintf(stderr, "failed to attach program!\n");
108 		exit(1);
109 	}
110 }
111 
112 static void strncmp_no_helper_setup(void)
113 {
114 	strncmp_setup();
115 	strncmp_attach_prog(ctx.skel->progs.strncmp_no_helper);
116 }
117 
118 static void strncmp_helper_setup(void)
119 {
120 	strncmp_setup();
121 	strncmp_attach_prog(ctx.skel->progs.strncmp_helper);
122 }
123 
124 static void *strncmp_producer(void *ctx)
125 {
126 	while (true)
127 		(void)syscall(__NR_getpgid);
128 	return NULL;
129 }
130 
131 static void *strncmp_consumer(void *ctx)
132 {
133 	return NULL;
134 }
135 
136 static void strncmp_measure(struct bench_res *res)
137 {
138 	res->hits = atomic_swap(&ctx.skel->bss->hits, 0);
139 }
140 
141 const struct bench bench_strncmp_no_helper = {
142 	.name = "strncmp-no-helper",
143 	.validate = strncmp_validate,
144 	.setup = strncmp_no_helper_setup,
145 	.producer_thread = strncmp_producer,
146 	.consumer_thread = strncmp_consumer,
147 	.measure = strncmp_measure,
148 	.report_progress = hits_drops_report_progress,
149 	.report_final = hits_drops_report_final,
150 };
151 
152 const struct bench bench_strncmp_helper = {
153 	.name = "strncmp-helper",
154 	.validate = strncmp_validate,
155 	.setup = strncmp_helper_setup,
156 	.producer_thread = strncmp_producer,
157 	.consumer_thread = strncmp_consumer,
158 	.measure = strncmp_measure,
159 	.report_progress = hits_drops_report_progress,
160 	.report_final = hits_drops_report_final,
161 };
162