1 /* 2 * 3 * builtin-bench.c 4 * 5 * General benchmarking subsystem provided by perf 6 * 7 * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> 8 * 9 */ 10 11 /* 12 * 13 * Available subsystem list: 14 * sched ... scheduler and IPC mechanism 15 * mem ... memory access performance 16 * 17 */ 18 19 #include "perf.h" 20 #include "util/util.h" 21 #include "util/parse-options.h" 22 #include "builtin.h" 23 #include "bench/bench.h" 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 struct bench_suite { 30 const char *name; 31 const char *summary; 32 int (*fn)(int, const char **, const char *); 33 }; 34 \ 35 /* sentinel: easy for help */ 36 #define suite_all { "all", "Test all benchmark suites", NULL } 37 38 #ifdef LIBNUMA_SUPPORT 39 static struct bench_suite numa_suites[] = { 40 { "mem", 41 "Benchmark for NUMA workloads", 42 bench_numa }, 43 suite_all, 44 { NULL, 45 NULL, 46 NULL } 47 }; 48 #endif 49 50 static struct bench_suite sched_suites[] = { 51 { "messaging", 52 "Benchmark for scheduler and IPC mechanisms", 53 bench_sched_messaging }, 54 { "pipe", 55 "Flood of communication over pipe() between two processes", 56 bench_sched_pipe }, 57 suite_all, 58 { NULL, 59 NULL, 60 NULL } 61 }; 62 63 static struct bench_suite mem_suites[] = { 64 { "memcpy", 65 "Simple memory copy in various ways", 66 bench_mem_memcpy }, 67 { "memset", 68 "Simple memory set in various ways", 69 bench_mem_memset }, 70 suite_all, 71 { NULL, 72 NULL, 73 NULL } 74 }; 75 76 struct bench_subsys { 77 const char *name; 78 const char *summary; 79 struct bench_suite *suites; 80 }; 81 82 static struct bench_subsys subsystems[] = { 83 #ifdef LIBNUMA_SUPPORT 84 { "numa", 85 "NUMA scheduling and MM behavior", 86 numa_suites }, 87 #endif 88 { "sched", 89 "scheduler and IPC mechanism", 90 sched_suites }, 91 { "mem", 92 "memory access performance", 93 mem_suites }, 94 { "all", /* sentinel: easy for help */ 95 "all benchmark subsystem", 96 NULL }, 97 { NULL, 98 NULL, 99 NULL } 100 }; 101 102 static void dump_suites(int subsys_index) 103 { 104 int i; 105 106 printf("# List of available suites for %s...\n\n", 107 subsystems[subsys_index].name); 108 109 for (i = 0; subsystems[subsys_index].suites[i].name; i++) 110 printf("%14s: %s\n", 111 subsystems[subsys_index].suites[i].name, 112 subsystems[subsys_index].suites[i].summary); 113 114 printf("\n"); 115 return; 116 } 117 118 static const char *bench_format_str; 119 int bench_format = BENCH_FORMAT_DEFAULT; 120 121 static const struct option bench_options[] = { 122 OPT_STRING('f', "format", &bench_format_str, "default", 123 "Specify format style"), 124 OPT_END() 125 }; 126 127 static const char * const bench_usage[] = { 128 "perf bench [<common options>] <subsystem> <suite> [<options>]", 129 NULL 130 }; 131 132 static void print_usage(void) 133 { 134 int i; 135 136 printf("Usage: \n"); 137 for (i = 0; bench_usage[i]; i++) 138 printf("\t%s\n", bench_usage[i]); 139 printf("\n"); 140 141 printf("# List of available subsystems...\n\n"); 142 143 for (i = 0; subsystems[i].name; i++) 144 printf("%14s: %s\n", 145 subsystems[i].name, subsystems[i].summary); 146 printf("\n"); 147 } 148 149 static int bench_str2int(const char *str) 150 { 151 if (!str) 152 return BENCH_FORMAT_DEFAULT; 153 154 if (!strcmp(str, BENCH_FORMAT_DEFAULT_STR)) 155 return BENCH_FORMAT_DEFAULT; 156 else if (!strcmp(str, BENCH_FORMAT_SIMPLE_STR)) 157 return BENCH_FORMAT_SIMPLE; 158 159 return BENCH_FORMAT_UNKNOWN; 160 } 161 162 static void all_suite(struct bench_subsys *subsys) /* FROM HERE */ 163 { 164 int i; 165 const char *argv[2]; 166 struct bench_suite *suites = subsys->suites; 167 168 argv[1] = NULL; 169 /* 170 * TODO: 171 * preparing preset parameters for 172 * embedded, ordinary PC, HPC, etc... 173 * will be helpful 174 */ 175 for (i = 0; suites[i].fn; i++) { 176 printf("# Running %s/%s benchmark...\n", 177 subsys->name, 178 suites[i].name); 179 fflush(stdout); 180 181 argv[1] = suites[i].name; 182 suites[i].fn(1, argv, NULL); 183 printf("\n"); 184 } 185 } 186 187 static void all_subsystem(void) 188 { 189 int i; 190 for (i = 0; subsystems[i].suites; i++) 191 all_suite(&subsystems[i]); 192 } 193 194 int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) 195 { 196 int i, j, status = 0; 197 198 if (argc < 2) { 199 /* No subsystem specified. */ 200 print_usage(); 201 goto end; 202 } 203 204 argc = parse_options(argc, argv, bench_options, bench_usage, 205 PARSE_OPT_STOP_AT_NON_OPTION); 206 207 bench_format = bench_str2int(bench_format_str); 208 if (bench_format == BENCH_FORMAT_UNKNOWN) { 209 printf("Unknown format descriptor:%s\n", bench_format_str); 210 goto end; 211 } 212 213 if (argc < 1) { 214 print_usage(); 215 goto end; 216 } 217 218 if (!strcmp(argv[0], "all")) { 219 all_subsystem(); 220 goto end; 221 } 222 223 for (i = 0; subsystems[i].name; i++) { 224 if (strcmp(subsystems[i].name, argv[0])) 225 continue; 226 227 if (argc < 2) { 228 /* No suite specified. */ 229 dump_suites(i); 230 goto end; 231 } 232 233 if (!strcmp(argv[1], "all")) { 234 all_suite(&subsystems[i]); 235 goto end; 236 } 237 238 for (j = 0; subsystems[i].suites[j].name; j++) { 239 if (strcmp(subsystems[i].suites[j].name, argv[1])) 240 continue; 241 242 if (bench_format == BENCH_FORMAT_DEFAULT) 243 printf("# Running %s/%s benchmark...\n", 244 subsystems[i].name, 245 subsystems[i].suites[j].name); 246 fflush(stdout); 247 status = subsystems[i].suites[j].fn(argc - 1, 248 argv + 1, prefix); 249 goto end; 250 } 251 252 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 253 dump_suites(i); 254 goto end; 255 } 256 257 printf("Unknown suite:%s for %s\n", argv[1], argv[0]); 258 status = 1; 259 goto end; 260 } 261 262 printf("Unknown subsystem:%s\n", argv[0]); 263 status = 1; 264 265 end: 266 return status; 267 } 268