Home | History | Annotate | Download | only in perf
      1 /*
      2  *
      3  * builtin-bench.c
      4  *
      5  * General benchmarking subsystem provided by perf
      6  *
      7  * Copyright (C) 2009, Hitoshi Mitake <mitake (at) 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