| /* | |
| * | |
| * builtin-bench.c | |
| * | |
| * General benchmarking subsystem provided by perf | |
| * | |
| * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | |
| * | |
| */ | |
| /* | |
| * | |
| * Available subsystem list: | |
| * sched ... scheduler and IPC mechanism | |
| * mem ... memory access performance | |
| * | |
| */ | |
| #include "perf.h" | |
| #include "util/util.h" | |
| #include "util/parse-options.h" | |
| #include "builtin.h" | |
| #include "bench/bench.h" | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| struct bench_suite { | |
| const char *name; | |
| const char *summary; | |
| int (*fn)(int, const char **, const char *); | |
| }; | |
| \ | |
| /* sentinel: easy for help */ | |
| #define suite_all { "all", "test all suite (pseudo suite)", NULL } | |
| static struct bench_suite sched_suites[] = { | |
| { "messaging", | |
| "Benchmark for scheduler and IPC mechanisms", | |
| bench_sched_messaging }, | |
| { "pipe", | |
| "Flood of communication over pipe() between two processes", | |
| bench_sched_pipe }, | |
| suite_all, | |
| { NULL, | |
| NULL, | |
| NULL } | |
| }; | |
| static struct bench_suite mem_suites[] = { | |
| { "memcpy", | |
| "Simple memory copy in various ways", | |
| bench_mem_memcpy }, | |
| suite_all, | |
| { NULL, | |
| NULL, | |
| NULL } | |
| }; | |
| struct bench_subsys { | |
| const char *name; | |
| const char *summary; | |
| struct bench_suite *suites; | |
| }; | |
| static struct bench_subsys subsystems[] = { | |
| { "sched", | |
| "scheduler and IPC mechanism", | |
| sched_suites }, | |
| { "mem", | |
| "memory access performance", | |
| mem_suites }, | |
| { "all", /* sentinel: easy for help */ | |
| "test all subsystem (pseudo subsystem)", | |
| NULL }, | |
| { NULL, | |
| NULL, | |
| NULL } | |
| }; | |
| static void dump_suites(int subsys_index) | |
| { | |
| int i; | |
| printf("# List of available suites for %s...\n\n", | |
| subsystems[subsys_index].name); | |
| for (i = 0; subsystems[subsys_index].suites[i].name; i++) | |
| printf("%14s: %s\n", | |
| subsystems[subsys_index].suites[i].name, | |
| subsystems[subsys_index].suites[i].summary); | |
| printf("\n"); | |
| return; | |
| } | |
| static const char *bench_format_str; | |
| int bench_format = BENCH_FORMAT_DEFAULT; | |
| static const struct option bench_options[] = { | |
| OPT_STRING('f', "format", &bench_format_str, "default", | |
| "Specify format style"), | |
| OPT_END() | |
| }; | |
| static const char * const bench_usage[] = { | |
| "perf bench [<common options>] <subsystem> <suite> [<options>]", | |
| NULL | |
| }; | |
| static void print_usage(void) | |
| { | |
| int i; | |
| printf("Usage: \n"); | |
| for (i = 0; bench_usage[i]; i++) | |
| printf("\t%s\n", bench_usage[i]); | |
| printf("\n"); | |
| printf("# List of available subsystems...\n\n"); | |
| for (i = 0; subsystems[i].name; i++) | |
| printf("%14s: %s\n", | |
| subsystems[i].name, subsystems[i].summary); | |
| printf("\n"); | |
| } | |
| static int bench_str2int(const char *str) | |
| { | |
| if (!str) | |
| return BENCH_FORMAT_DEFAULT; | |
| if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR)) | |
| return BENCH_FORMAT_DEFAULT; | |
| else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR)) | |
| return BENCH_FORMAT_SIMPLE; | |
| return BENCH_FORMAT_UNKNOWN; | |
| } | |
| static void all_suite(struct bench_subsys *subsys) /* FROM HERE */ | |
| { | |
| int i; | |
| const char *argv[2]; | |
| struct bench_suite *suites = subsys->suites; | |
| argv[1] = NULL; | |
| /* | |
| * TODO: | |
| * preparing preset parameters for | |
| * embedded, ordinary PC, HPC, etc... | |
| * will be helpful | |
| */ | |
| for (i = 0; suites[i].fn; i++) { | |
| printf("# Running %s/%s benchmark...\n", | |
| subsys->name, | |
| suites[i].name); | |
| argv[1] = suites[i].name; | |
| suites[i].fn(1, argv, NULL); | |
| printf("\n"); | |
| } | |
| } | |
| static void all_subsystem(void) | |
| { | |
| int i; | |
| for (i = 0; subsystems[i].suites; i++) | |
| all_suite(&subsystems[i]); | |
| } | |
| int cmd_bench(int argc, const char **argv, const char *prefix __used) | |
| { | |
| int i, j, status = 0; | |
| if (argc < 2) { | |
| /* No subsystem specified. */ | |
| print_usage(); | |
| goto end; | |
| } | |
| argc = parse_options(argc, argv, bench_options, bench_usage, | |
| PARSE_OPT_STOP_AT_NON_OPTION); | |
| bench_format = bench_str2int(bench_format_str); | |
| if (bench_format == BENCH_FORMAT_UNKNOWN) { | |
| printf("Unknown format descriptor:%s\n", bench_format_str); | |
| goto end; | |
| } | |
| if (argc < 1) { | |
| print_usage(); | |
| goto end; | |
| } | |
| if (!strcmp(argv[0], "all")) { | |
| all_subsystem(); | |
| goto end; | |
| } | |
| for (i = 0; subsystems[i].name; i++) { | |
| if (strcmp(subsystems[i].name, argv[0])) | |
| continue; | |
| if (argc < 2) { | |
| /* No suite specified. */ | |
| dump_suites(i); | |
| goto end; | |
| } | |
| if (!strcmp(argv[1], "all")) { | |
| all_suite(&subsystems[i]); | |
| goto end; | |
| } | |
| for (j = 0; subsystems[i].suites[j].name; j++) { | |
| if (strcmp(subsystems[i].suites[j].name, argv[1])) | |
| continue; | |
| if (bench_format == BENCH_FORMAT_DEFAULT) | |
| printf("# Running %s/%s benchmark...\n", | |
| subsystems[i].name, | |
| subsystems[i].suites[j].name); | |
| status = subsystems[i].suites[j].fn(argc - 1, | |
| argv + 1, prefix); | |
| goto end; | |
| } | |
| if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { | |
| dump_suites(i); | |
| goto end; | |
| } | |
| printf("Unknown suite:%s for %s\n", argv[1], argv[0]); | |
| status = 1; | |
| goto end; | |
| } | |
| printf("Unknown subsystem:%s\n", argv[0]); | |
| status = 1; | |
| end: | |
| return status; | |
| } |