~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_lookup.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* 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 */
 11 static 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 
 20 static 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 
 34 enum {
 35         ARG_KEY_SIZE = 8001,
 36         ARG_MAP_FLAGS,
 37         ARG_MAX_ENTRIES,
 38         ARG_NR_ENTRIES,
 39         ARG_NR_LOOPS,
 40 };
 41 
 42 static 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 
 56 static 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 
109 const struct argp bench_hashmap_lookup_argp = {
110         .options = opts,
111         .parser = parse_arg,
112 };
113 
114 static 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 
128 static void *producer(void *input)
129 {
130         while (true) {
131                 /* trigger the bpf program */
132                 syscall(__NR_getpgid);
133         }
134         return NULL;
135 }
136 
137 static void measure(struct bench_res *res)
138 {
139 }
140 
141 static inline void patch_key(u32 i, u32 *key)
142 {
143 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
144         *key = i + 1;
145 #else
146         *key = __builtin_bswap32(i + 1);
147 #endif
148         /* the rest of key is random */
149 }
150 
151 static 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 
200 static 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 
208 static 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 
240 static 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                         else
258                                 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 
268 const 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php