1 /* 2 * builtin-bench.c 3 * 4 * General benchmarking collections provided by perf 5 * 6 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 7 */ 8 9 /* 10 * Available benchmark collection list: 11 * 12 * sched ... scheduler and IPC performance 13 * mem ... memory access performance 14 * numa ... NUMA scheduling and MM performance 15 * futex ... Futex performance 16 */ 17 #include "perf.h" 18 #include "util/util.h" 19 #include "util/parse-options.h" 20 #include "builtin.h" 21 #include "bench/bench.h" 22 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <sys/prctl.h> 27 28 typedef int (*bench_fn_t)(int argc, const char **argv, const char *prefix); 29 30 struct bench { 31 const char *name; 32 const char *summary; 33 bench_fn_t fn; 34 }; 35 36 #ifdef HAVE_LIBNUMA_SUPPORT 37 static struct bench numa_benchmarks[] = { 38 { "mem", "Benchmark for NUMA workloads", bench_numa }, 39 { "all", "Test all NUMA benchmarks", NULL }, 40 { NULL, NULL, NULL } 41 }; 42 #endif 43 44 static struct bench sched_benchmarks[] = { 45 { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging }, 46 { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe }, 47 { "all", "Test all scheduler benchmarks", NULL }, 48 { NULL, NULL, NULL } 49 }; 50 51 static struct bench mem_benchmarks[] = { 52 { "memcpy", "Benchmark for memcpy()", bench_mem_memcpy }, 53 { "memset", "Benchmark for memset() tests", bench_mem_memset }, 54 { "all", "Test all memory benchmarks", NULL }, 55 { NULL, NULL, NULL } 56 }; 57 58 static struct bench futex_benchmarks[] = { 59 { "hash", "Benchmark for futex hash table", bench_futex_hash }, 60 { "wake", "Benchmark for futex wake calls", bench_futex_wake }, 61 { "all", "Test all futex benchmarks", NULL }, 62 { NULL, NULL, NULL } 63 }; 64 65 struct collection { 66 const char *name; 67 const char *summary; 68 struct bench *benchmarks; 69 }; 70 71 static struct collection collections[] = { 72 { "sched", "Scheduler and IPC benchmarks", sched_benchmarks }, 73 { "mem", "Memory access benchmarks", mem_benchmarks }, 74 #ifdef HAVE_LIBNUMA_SUPPORT 75 { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks }, 76 #endif 77 {"futex", "Futex stressing benchmarks", futex_benchmarks }, 78 { "all", "All benchmarks", NULL }, 79 { NULL, NULL, NULL } 80 }; 81 82 /* Iterate over all benchmark collections: */ 83 #define for_each_collection(coll) \ 84 for (coll = collections; coll->name; coll++) 85 86 /* Iterate over all benchmarks within a collection: */ 87 #define for_each_bench(coll, bench) \ 88 for (bench = coll->benchmarks; bench->name; bench++) 89 90 static void dump_benchmarks(struct collection *coll) 91 { 92 struct bench *bench; 93 94 printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name); 95 96 for_each_bench(coll, bench) 97 printf("%14s: %s\n", bench->name, bench->summary); 98 99 printf("\n"); 100 } 101 102 static const char *bench_format_str; 103 104 /* Output/formatting style, exported to benchmark modules: */ 105 int bench_format = BENCH_FORMAT_DEFAULT; 106 107 static const struct option bench_options[] = { 108 OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"), 109 OPT_END() 110 }; 111 112 static const char * const bench_usage[] = { 113 "perf bench [<common options>] <collection> <benchmark> [<options>]", 114 NULL 115 }; 116 117 static void print_usage(void) 118 { 119 struct collection *coll; 120 int i; 121 122 printf("Usage: \n"); 123 for (i = 0; bench_usage[i]; i++) 124 printf("\t%s\n", bench_usage[i]); 125 printf("\n"); 126 127 printf(" # List of all available benchmark collections:\n\n"); 128 129 for_each_collection(coll) 130 printf("%14s: %s\n", coll->name, coll->summary); 131 printf("\n"); 132 } 133 134 static int bench_str2int(const char *str) 135 { 136 if (!str) 137 return BENCH_FORMAT_DEFAULT; 138 139 if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR)) 140 return BENCH_FORMAT_DEFAULT; 141 else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR)) 142 return BENCH_FORMAT_SIMPLE; 143 144 return BENCH_FORMAT_UNKNOWN; 145 } 146 147 /* 148 * Run a specific benchmark but first rename the running task's ->comm[] 149 * to something meaningful: 150 */ 151 static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn, 152 int argc, const char **argv, const char *prefix) 153 { 154 int size; 155 char *name; 156 int ret; 157 158 size = strlen(coll_name) + 1 + strlen(bench_name) + 1; 159 160 name = zalloc(size); 161 BUG_ON(!name); 162 163 scnprintf(name, size, "%s-%s", coll_name, bench_name); 164 165 prctl(PR_SET_NAME, name); 166 argv[0] = name; 167 168 ret = fn(argc, argv, prefix); 169 170 free(name); 171 172 return ret; 173 } 174 175 static void run_collection(struct collection *coll) 176 { 177 struct bench *bench; 178 const char *argv[2]; 179 180 argv[1] = NULL; 181 /* 182 * TODO: 183 * 184 * Preparing preset parameters for 185 * embedded, ordinary PC, HPC, etc... 186 * would be helpful. 187 */ 188 for_each_bench(coll, bench) { 189 if (!bench->fn) 190 break; 191 printf("# Running %s/%s benchmark...\n", coll->name, bench->name); 192 fflush(stdout); 193 194 argv[1] = bench->name; 195 run_bench(coll->name, bench->name, bench->fn, 1, argv, NULL); 196 printf("\n"); 197 } 198 } 199 200 static void run_all_collections(void) 201 { 202 struct collection *coll; 203 204 for_each_collection(coll) 205 run_collection(coll); 206 } 207 208 int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) 209 { 210 struct collection *coll; 211 int ret = 0; 212 213 if (argc < 2) { 214 /* No collection specified. */ 215 print_usage(); 216 goto end; 217 } 218 219 argc = parse_options(argc, argv, bench_options, bench_usage, 220 PARSE_OPT_STOP_AT_NON_OPTION); 221 222 bench_format = bench_str2int(bench_format_str); 223 if (bench_format == BENCH_FORMAT_UNKNOWN) { 224 printf("Unknown format descriptor: '%s'\n", bench_format_str); 225 goto end; 226 } 227 228 if (argc < 1) { 229 print_usage(); 230 goto end; 231 } 232 233 if (!strcmp(argv[0], "all")) { 234 run_all_collections(); 235 goto end; 236 } 237 238 for_each_collection(coll) { 239 struct bench *bench; 240 241 if (strcmp(coll->name, argv[0])) 242 continue; 243 244 if (argc < 2) { 245 /* No bench specified. */ 246 dump_benchmarks(coll); 247 goto end; 248 } 249 250 if (!strcmp(argv[1], "all")) { 251 run_collection(coll); 252 goto end; 253 } 254 255 for_each_bench(coll, bench) { 256 if (strcmp(bench->name, argv[1])) 257 continue; 258 259 if (bench_format == BENCH_FORMAT_DEFAULT) 260 printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name); 261 fflush(stdout); 262 ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1, prefix); 263 goto end; 264 } 265 266 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 267 dump_benchmarks(coll); 268 goto end; 269 } 270 271 printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]); 272 ret = 1; 273 goto end; 274 } 275 276 printf("Unknown collection: '%s'\n", argv[0]); 277 ret = 1; 278 279 end: 280 return ret; 281 } 282