Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * builtin-bench.c
0004  *
0005  * General benchmarking collections provided by perf
0006  *
0007  * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
0008  */
0009 
0010 /*
0011  * Available benchmark collection list:
0012  *
0013  *  sched ... scheduler and IPC performance
0014  *  syscall ... System call performance
0015  *  mem   ... memory access performance
0016  *  numa  ... NUMA scheduling and MM performance
0017  *  futex ... Futex performance
0018  *  epoll ... Event poll performance
0019  */
0020 #include <subcmd/parse-options.h>
0021 #include "builtin.h"
0022 #include "bench/bench.h"
0023 
0024 #include <stdio.h>
0025 #include <stdlib.h>
0026 #include <string.h>
0027 #include <sys/prctl.h>
0028 #include <linux/zalloc.h>
0029 
0030 typedef int (*bench_fn_t)(int argc, const char **argv);
0031 
0032 struct bench {
0033     const char  *name;
0034     const char  *summary;
0035     bench_fn_t  fn;
0036 };
0037 
0038 #ifdef HAVE_LIBNUMA_SUPPORT
0039 static struct bench numa_benchmarks[] = {
0040     { "mem",    "Benchmark for NUMA workloads",         bench_numa      },
0041     { "all",    "Run all NUMA benchmarks",          NULL            },
0042     { NULL,     NULL,                       NULL            }
0043 };
0044 #endif
0045 
0046 static struct bench sched_benchmarks[] = {
0047     { "messaging",  "Benchmark for scheduling and IPC",     bench_sched_messaging   },
0048     { "pipe",   "Benchmark for pipe() between two processes",   bench_sched_pipe    },
0049     { "all",    "Run all scheduler benchmarks",     NULL            },
0050     { NULL,     NULL,                       NULL            }
0051 };
0052 
0053 static struct bench syscall_benchmarks[] = {
0054     { "basic",  "Benchmark for basic getppid(2) calls",     bench_syscall_basic },
0055     { "all",    "Run all syscall benchmarks",           NULL            },
0056     { NULL,     NULL,                       NULL            },
0057 };
0058 
0059 static struct bench mem_benchmarks[] = {
0060     { "memcpy", "Benchmark for memcpy() functions",     bench_mem_memcpy    },
0061     { "memset", "Benchmark for memset() functions",     bench_mem_memset    },
0062     { "find_bit",   "Benchmark for find_bit() functions",       bench_mem_find_bit  },
0063     { "all",    "Run all memory access benchmarks",     NULL            },
0064     { NULL,     NULL,                       NULL            }
0065 };
0066 
0067 static struct bench futex_benchmarks[] = {
0068     { "hash",   "Benchmark for futex hash table",               bench_futex_hash    },
0069     { "wake",   "Benchmark for futex wake calls",               bench_futex_wake    },
0070     { "wake-parallel", "Benchmark for parallel futex wake calls",   bench_futex_wake_parallel },
0071     { "requeue",    "Benchmark for futex requeue calls",            bench_futex_requeue },
0072     /* pi-futexes */
0073     { "lock-pi",    "Benchmark for futex lock_pi calls",            bench_futex_lock_pi },
0074     { "all",    "Run all futex benchmarks",         NULL            },
0075     { NULL,     NULL,                       NULL            }
0076 };
0077 
0078 #ifdef HAVE_EVENTFD_SUPPORT
0079 static struct bench epoll_benchmarks[] = {
0080     { "wait",   "Benchmark epoll concurrent epoll_waits",       bench_epoll_wait    },
0081     { "ctl",    "Benchmark epoll concurrent epoll_ctls",        bench_epoll_ctl     },
0082     { "all",    "Run all futex benchmarks",         NULL            },
0083     { NULL,     NULL,                       NULL            }
0084 };
0085 #endif // HAVE_EVENTFD_SUPPORT
0086 
0087 static struct bench internals_benchmarks[] = {
0088     { "synthesize", "Benchmark perf event synthesis",   bench_synthesize    },
0089     { "kallsyms-parse", "Benchmark kallsyms parsing",   bench_kallsyms_parse    },
0090     { "inject-build-id", "Benchmark build-id injection",    bench_inject_build_id   },
0091     { "evlist-open-close", "Benchmark evlist open and close",   bench_evlist_open_close },
0092     { NULL,     NULL,                   NULL            }
0093 };
0094 
0095 static struct bench breakpoint_benchmarks[] = {
0096     { "thread", "Benchmark thread start/finish with breakpoints", bench_breakpoint_thread},
0097     { "enable", "Benchmark breakpoint enable/disable", bench_breakpoint_enable},
0098     { "all", "Run all breakpoint benchmarks", NULL},
0099     { NULL, NULL, NULL },
0100 };
0101 
0102 struct collection {
0103     const char  *name;
0104     const char  *summary;
0105     struct bench    *benchmarks;
0106 };
0107 
0108 static struct collection collections[] = {
0109     { "sched",  "Scheduler and IPC benchmarks",         sched_benchmarks    },
0110     { "syscall",    "System call benchmarks",           syscall_benchmarks  },
0111     { "mem",    "Memory access benchmarks",         mem_benchmarks      },
0112 #ifdef HAVE_LIBNUMA_SUPPORT
0113     { "numa",   "NUMA scheduling and MM benchmarks",        numa_benchmarks     },
0114 #endif
0115     {"futex",       "Futex stressing benchmarks",                   futex_benchmarks        },
0116 #ifdef HAVE_EVENTFD_SUPPORT
0117     {"epoll",       "Epoll stressing benchmarks",                   epoll_benchmarks        },
0118 #endif
0119     { "internals",  "Perf-internals benchmarks",            internals_benchmarks    },
0120     { "breakpoint", "Breakpoint benchmarks",            breakpoint_benchmarks   },
0121     { "all",    "All benchmarks",               NULL            },
0122     { NULL,     NULL,                       NULL            }
0123 };
0124 
0125 /* Iterate over all benchmark collections: */
0126 #define for_each_collection(coll) \
0127     for (coll = collections; coll->name; coll++)
0128 
0129 /* Iterate over all benchmarks within a collection: */
0130 #define for_each_bench(coll, bench) \
0131     for (bench = coll->benchmarks; bench && bench->name; bench++)
0132 
0133 static void dump_benchmarks(struct collection *coll)
0134 {
0135     struct bench *bench;
0136 
0137     printf("\n        # List of available benchmarks for collection '%s':\n\n", coll->name);
0138 
0139     for_each_bench(coll, bench)
0140         printf("%14s: %s\n", bench->name, bench->summary);
0141 
0142     printf("\n");
0143 }
0144 
0145 static const char *bench_format_str;
0146 
0147 /* Output/formatting style, exported to benchmark modules: */
0148 int bench_format = BENCH_FORMAT_DEFAULT;
0149 unsigned int bench_repeat = 10; /* default number of times to repeat the run */
0150 
0151 static const struct option bench_options[] = {
0152     OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
0153     OPT_UINTEGER('r', "repeat",  &bench_repeat,   "Specify amount of times to repeat the run"),
0154     OPT_END()
0155 };
0156 
0157 static const char * const bench_usage[] = {
0158     "perf bench [<common options>] <collection> <benchmark> [<options>]",
0159     NULL
0160 };
0161 
0162 static void print_usage(void)
0163 {
0164     struct collection *coll;
0165     int i;
0166 
0167     printf("Usage: \n");
0168     for (i = 0; bench_usage[i]; i++)
0169         printf("\t%s\n", bench_usage[i]);
0170     printf("\n");
0171 
0172     printf("        # List of all available benchmark collections:\n\n");
0173 
0174     for_each_collection(coll)
0175         printf("%14s: %s\n", coll->name, coll->summary);
0176     printf("\n");
0177 }
0178 
0179 static int bench_str2int(const char *str)
0180 {
0181     if (!str)
0182         return BENCH_FORMAT_DEFAULT;
0183 
0184     if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR))
0185         return BENCH_FORMAT_DEFAULT;
0186     else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR))
0187         return BENCH_FORMAT_SIMPLE;
0188 
0189     return BENCH_FORMAT_UNKNOWN;
0190 }
0191 
0192 /*
0193  * Run a specific benchmark but first rename the running task's ->comm[]
0194  * to something meaningful:
0195  */
0196 static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
0197              int argc, const char **argv)
0198 {
0199     int size;
0200     char *name;
0201     int ret;
0202 
0203     size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
0204 
0205     name = zalloc(size);
0206     BUG_ON(!name);
0207 
0208     scnprintf(name, size, "%s-%s", coll_name, bench_name);
0209 
0210     prctl(PR_SET_NAME, name);
0211     argv[0] = name;
0212 
0213     ret = fn(argc, argv);
0214 
0215     free(name);
0216 
0217     return ret;
0218 }
0219 
0220 static void run_collection(struct collection *coll)
0221 {
0222     struct bench *bench;
0223     const char *argv[2];
0224 
0225     argv[1] = NULL;
0226     /*
0227      * TODO:
0228      *
0229      * Preparing preset parameters for
0230      * embedded, ordinary PC, HPC, etc...
0231      * would be helpful.
0232      */
0233     for_each_bench(coll, bench) {
0234         if (!bench->fn)
0235             break;
0236         printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
0237 
0238         argv[1] = bench->name;
0239         run_bench(coll->name, bench->name, bench->fn, 1, argv);
0240         printf("\n");
0241     }
0242 }
0243 
0244 static void run_all_collections(void)
0245 {
0246     struct collection *coll;
0247 
0248     for_each_collection(coll)
0249         run_collection(coll);
0250 }
0251 
0252 int cmd_bench(int argc, const char **argv)
0253 {
0254     struct collection *coll;
0255     int ret = 0;
0256 
0257     /* Unbuffered output */
0258     setvbuf(stdout, NULL, _IONBF, 0);
0259 
0260     if (argc < 2) {
0261         /* No collection specified. */
0262         print_usage();
0263         goto end;
0264     }
0265 
0266     argc = parse_options(argc, argv, bench_options, bench_usage,
0267                  PARSE_OPT_STOP_AT_NON_OPTION);
0268 
0269     bench_format = bench_str2int(bench_format_str);
0270     if (bench_format == BENCH_FORMAT_UNKNOWN) {
0271         printf("Unknown format descriptor: '%s'\n", bench_format_str);
0272         goto end;
0273     }
0274 
0275     if (bench_repeat == 0) {
0276         printf("Invalid repeat option: Must specify a positive value\n");
0277         goto end;
0278     }
0279 
0280     if (argc < 1) {
0281         print_usage();
0282         goto end;
0283     }
0284 
0285     if (!strcmp(argv[0], "all")) {
0286         run_all_collections();
0287         goto end;
0288     }
0289 
0290     for_each_collection(coll) {
0291         struct bench *bench;
0292 
0293         if (strcmp(coll->name, argv[0]))
0294             continue;
0295 
0296         if (argc < 2) {
0297             /* No bench specified. */
0298             dump_benchmarks(coll);
0299             goto end;
0300         }
0301 
0302         if (!strcmp(argv[1], "all")) {
0303             run_collection(coll);
0304             goto end;
0305         }
0306 
0307         for_each_bench(coll, bench) {
0308             if (strcmp(bench->name, argv[1]))
0309                 continue;
0310 
0311             if (bench_format == BENCH_FORMAT_DEFAULT)
0312                 printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
0313             ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
0314             goto end;
0315         }
0316 
0317         if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
0318             dump_benchmarks(coll);
0319             goto end;
0320         }
0321 
0322         printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
0323         ret = 1;
0324         goto end;
0325     }
0326 
0327     printf("Unknown collection: '%s'\n", argv[0]);
0328     ret = 1;
0329 
0330 end:
0331     return ret;
0332 }