Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftest/bpf/benchs: Enhance argp parsing

To parse command line the bench utility uses the argp_parse() function. This
function takes as an argument a parent 'struct argp' structure which defines
common command line options and an array of children 'struct argp' structures
which defines additional command line options for particular benchmarks. This
implementation doesn't allow benchmarks to share option names, e.g., if two
benchmarks want to use, say, the --option option, then only one of them will
succeed (the first one encountered in the array). This will be convenient if
same option names could be used in different benchmarks (with the same
semantics, e.g., --nr_loops=N).

Fix this by calling the argp_parse() function twice. The first call is the same
as it was before, with all children argps, and helps to find the benchmark name
and to print a combined help message if anything is wrong. Given the name, we
can call the argp_parse the second time, but now the children array points only
to a correct benchmark thus always calling the correct parsers. (If there's no
a specific list of arguments, then only one call to argp_parse will be done.)

Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20230213091519.1202813-4-aspsk@isovalent.com

authored by

Anton Protopopov and committed by
Andrii Nakryiko
22ff7aea 2f1c5963

+51 -10
+34 -10
tools/testing/selftests/bpf/bench.c
··· 287 287 {}, 288 288 }; 289 289 290 + /* Make pos_args global, so that we can run argp_parse twice, if necessary */ 291 + static int pos_args; 292 + 290 293 static error_t parse_arg(int key, char *arg, struct argp_state *state) 291 294 { 292 - static int pos_args; 293 - 294 295 switch (key) { 295 296 case 'v': 296 297 env.verbose = true; ··· 360 359 return 0; 361 360 } 362 361 363 - static void parse_cmdline_args(int argc, char **argv) 362 + static void parse_cmdline_args_init(int argc, char **argv) 364 363 { 365 364 static const struct argp argp = { 366 365 .options = opts, ··· 370 369 }; 371 370 if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) 372 371 exit(1); 373 - if (!env.list && !env.bench_name) { 374 - argp_help(&argp, stderr, ARGP_HELP_DOC, "bench"); 375 - exit(1); 372 + } 373 + 374 + static void parse_cmdline_args_final(int argc, char **argv) 375 + { 376 + struct argp_child bench_parsers[2] = {}; 377 + const struct argp argp = { 378 + .options = opts, 379 + .parser = parse_arg, 380 + .doc = argp_program_doc, 381 + .children = bench_parsers, 382 + }; 383 + 384 + /* Parse arguments the second time with the correct set of parsers */ 385 + if (bench->argp) { 386 + bench_parsers[0].argp = bench->argp; 387 + bench_parsers[0].header = bench->name; 388 + pos_args = 0; 389 + if (argp_parse(&argp, argc, argv, 0, NULL, NULL)) 390 + exit(1); 376 391 } 377 392 } 378 393 ··· 548 531 &bench_local_storage_tasks_trace, 549 532 }; 550 533 551 - static void setup_benchmark() 534 + static void find_benchmark(void) 552 535 { 553 - int i, err; 536 + int i; 554 537 555 538 if (!env.bench_name) { 556 539 fprintf(stderr, "benchmark name is not specified\n"); 557 540 exit(1); 558 541 } 559 - 560 542 for (i = 0; i < ARRAY_SIZE(benchs); i++) { 561 543 if (strcmp(benchs[i]->name, env.bench_name) == 0) { 562 544 bench = benchs[i]; ··· 566 550 fprintf(stderr, "benchmark '%s' not found\n", env.bench_name); 567 551 exit(1); 568 552 } 553 + } 554 + 555 + static void setup_benchmark(void) 556 + { 557 + int i, err; 569 558 570 559 printf("Setting up benchmark '%s'...\n", bench->name); 571 560 ··· 642 621 643 622 int main(int argc, char **argv) 644 623 { 645 - parse_cmdline_args(argc, argv); 624 + parse_cmdline_args_init(argc, argv); 646 625 647 626 if (env.list) { 648 627 int i; ··· 653 632 } 654 633 return 0; 655 634 } 635 + 636 + find_benchmark(); 637 + parse_cmdline_args_final(argc, argv); 656 638 657 639 setup_benchmark(); 658 640
+1
tools/testing/selftests/bpf/bench.h
··· 47 47 48 48 struct bench { 49 49 const char *name; 50 + const struct argp *argp; 50 51 void (*validate)(void); 51 52 void (*setup)(void); 52 53 void *(*producer_thread)(void *ctx);
+5
tools/testing/selftests/bpf/benchs/bench_bloom_filter_map.c
··· 428 428 429 429 const struct bench bench_bloom_lookup = { 430 430 .name = "bloom-lookup", 431 + .argp = &bench_bloom_map_argp, 431 432 .validate = validate, 432 433 .setup = bloom_lookup_setup, 433 434 .producer_thread = producer, ··· 440 439 441 440 const struct bench bench_bloom_update = { 442 441 .name = "bloom-update", 442 + .argp = &bench_bloom_map_argp, 443 443 .validate = validate, 444 444 .setup = bloom_update_setup, 445 445 .producer_thread = producer, ··· 452 450 453 451 const struct bench bench_bloom_false_positive = { 454 452 .name = "bloom-false-positive", 453 + .argp = &bench_bloom_map_argp, 455 454 .validate = validate, 456 455 .setup = false_positive_setup, 457 456 .producer_thread = producer, ··· 464 461 465 462 const struct bench bench_hashmap_without_bloom = { 466 463 .name = "hashmap-without-bloom", 464 + .argp = &bench_bloom_map_argp, 467 465 .validate = validate, 468 466 .setup = hashmap_no_bloom_setup, 469 467 .producer_thread = producer, ··· 476 472 477 473 const struct bench bench_hashmap_with_bloom = { 478 474 .name = "hashmap-with-bloom", 475 + .argp = &bench_bloom_map_argp, 479 476 .validate = validate, 480 477 .setup = hashmap_with_bloom_setup, 481 478 .producer_thread = producer,
+1
tools/testing/selftests/bpf/benchs/bench_bpf_loop.c
··· 95 95 96 96 const struct bench bench_bpf_loop = { 97 97 .name = "bpf-loop", 98 + .argp = &bench_bpf_loop_argp, 98 99 .validate = validate, 99 100 .setup = setup, 100 101 .producer_thread = producer,
+3
tools/testing/selftests/bpf/benchs/bench_local_storage.c
··· 255 255 */ 256 256 const struct bench bench_local_storage_cache_seq_get = { 257 257 .name = "local-storage-cache-seq-get", 258 + .argp = &bench_local_storage_argp, 258 259 .validate = validate, 259 260 .setup = local_storage_cache_get_setup, 260 261 .producer_thread = producer, ··· 267 266 268 267 const struct bench bench_local_storage_cache_interleaved_get = { 269 268 .name = "local-storage-cache-int-get", 269 + .argp = &bench_local_storage_argp, 270 270 .validate = validate, 271 271 .setup = local_storage_cache_get_interleaved_setup, 272 272 .producer_thread = producer, ··· 279 277 280 278 const struct bench bench_local_storage_cache_hashmap_control = { 281 279 .name = "local-storage-cache-hashmap-control", 280 + .argp = &bench_local_storage_argp, 282 281 .validate = validate, 283 282 .setup = hashmap_setup, 284 283 .producer_thread = producer,
+1
tools/testing/selftests/bpf/benchs/bench_local_storage_rcu_tasks_trace.c
··· 271 271 */ 272 272 const struct bench bench_local_storage_tasks_trace = { 273 273 .name = "local-storage-tasks-trace", 274 + .argp = &bench_local_storage_rcu_tasks_trace_argp, 274 275 .validate = validate, 275 276 .setup = local_storage_tasks_trace_setup, 276 277 .producer_thread = producer,
+4
tools/testing/selftests/bpf/benchs/bench_ringbufs.c
··· 518 518 519 519 const struct bench bench_rb_libbpf = { 520 520 .name = "rb-libbpf", 521 + .argp = &bench_ringbufs_argp, 521 522 .validate = bufs_validate, 522 523 .setup = ringbuf_libbpf_setup, 523 524 .producer_thread = bufs_sample_producer, ··· 530 529 531 530 const struct bench bench_rb_custom = { 532 531 .name = "rb-custom", 532 + .argp = &bench_ringbufs_argp, 533 533 .validate = bufs_validate, 534 534 .setup = ringbuf_custom_setup, 535 535 .producer_thread = bufs_sample_producer, ··· 542 540 543 541 const struct bench bench_pb_libbpf = { 544 542 .name = "pb-libbpf", 543 + .argp = &bench_ringbufs_argp, 545 544 .validate = bufs_validate, 546 545 .setup = perfbuf_libbpf_setup, 547 546 .producer_thread = bufs_sample_producer, ··· 554 551 555 552 const struct bench bench_pb_custom = { 556 553 .name = "pb-custom", 554 + .argp = &bench_ringbufs_argp, 557 555 .validate = bufs_validate, 558 556 .setup = perfbuf_libbpf_setup, 559 557 .producer_thread = bufs_sample_producer,
+2
tools/testing/selftests/bpf/benchs/bench_strncmp.c
··· 140 140 141 141 const struct bench bench_strncmp_no_helper = { 142 142 .name = "strncmp-no-helper", 143 + .argp = &bench_strncmp_argp, 143 144 .validate = strncmp_validate, 144 145 .setup = strncmp_no_helper_setup, 145 146 .producer_thread = strncmp_producer, ··· 152 151 153 152 const struct bench bench_strncmp_helper = { 154 153 .name = "strncmp-helper", 154 + .argp = &bench_strncmp_argp, 155 155 .validate = strncmp_validate, 156 156 .setup = strncmp_helper_setup, 157 157 .producer_thread = strncmp_producer,