linux/tools/perf/builtin-bench.c
Arnaldo Carvalho de Melo 0ac25fd0a0 perf tools: Remove perf.h from source files not needing it
With the movement of lots of stuff out of perf.h to other headers we
ended up not needing it in lots of places, remove it from those places.

Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lkml.kernel.org/n/tip-c718m0sxxwp73lp9d8vpihb4@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2019-08-29 17:38:32 -03:00

306 lines
7.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* builtin-bench.c
*
* General benchmarking collections provided by perf
*
* Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
*/
/*
* Available benchmark collection list:
*
* sched ... scheduler and IPC performance
* mem ... memory access performance
* numa ... NUMA scheduling and MM performance
* futex ... Futex performance
* epoll ... Event poll performance
*/
#include <subcmd/parse-options.h>
#include "builtin.h"
#include "bench/bench.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <linux/zalloc.h>
typedef int (*bench_fn_t)(int argc, const char **argv);
struct bench {
const char *name;
const char *summary;
bench_fn_t fn;
};
#ifdef HAVE_LIBNUMA_SUPPORT
static struct bench numa_benchmarks[] = {
{ "mem", "Benchmark for NUMA workloads", bench_numa },
{ "all", "Run all NUMA benchmarks", NULL },
{ NULL, NULL, NULL }
};
#endif
static struct bench sched_benchmarks[] = {
{ "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging },
{ "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe },
{ "all", "Run all scheduler benchmarks", NULL },
{ NULL, NULL, NULL }
};
static struct bench mem_benchmarks[] = {
{ "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy },
{ "memset", "Benchmark for memset() functions", bench_mem_memset },
{ "all", "Run all memory access benchmarks", NULL },
{ NULL, NULL, NULL }
};
static struct bench futex_benchmarks[] = {
{ "hash", "Benchmark for futex hash table", bench_futex_hash },
{ "wake", "Benchmark for futex wake calls", bench_futex_wake },
{ "wake-parallel", "Benchmark for parallel futex wake calls", bench_futex_wake_parallel },
{ "requeue", "Benchmark for futex requeue calls", bench_futex_requeue },
/* pi-futexes */
{ "lock-pi", "Benchmark for futex lock_pi calls", bench_futex_lock_pi },
{ "all", "Run all futex benchmarks", NULL },
{ NULL, NULL, NULL }
};
#ifdef HAVE_EVENTFD
static struct bench epoll_benchmarks[] = {
{ "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait },
{ "ctl", "Benchmark epoll concurrent epoll_ctls", bench_epoll_ctl },
{ "all", "Run all futex benchmarks", NULL },
{ NULL, NULL, NULL }
};
#endif // HAVE_EVENTFD
struct collection {
const char *name;
const char *summary;
struct bench *benchmarks;
};
static struct collection collections[] = {
{ "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
{ "mem", "Memory access benchmarks", mem_benchmarks },
#ifdef HAVE_LIBNUMA_SUPPORT
{ "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
#endif
{"futex", "Futex stressing benchmarks", futex_benchmarks },
#ifdef HAVE_EVENTFD
{"epoll", "Epoll stressing benchmarks", epoll_benchmarks },
#endif
{ "all", "All benchmarks", NULL },
{ NULL, NULL, NULL }
};
/* Iterate over all benchmark collections: */
#define for_each_collection(coll) \
for (coll = collections; coll->name; coll++)
/* Iterate over all benchmarks within a collection: */
#define for_each_bench(coll, bench) \
for (bench = coll->benchmarks; bench && bench->name; bench++)
static void dump_benchmarks(struct collection *coll)
{
struct bench *bench;
printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name);
for_each_bench(coll, bench)
printf("%14s: %s\n", bench->name, bench->summary);
printf("\n");
}
static const char *bench_format_str;
/* Output/formatting style, exported to benchmark modules: */
int bench_format = BENCH_FORMAT_DEFAULT;
unsigned int bench_repeat = 10; /* default number of times to repeat the run */
static const struct option bench_options[] = {
OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"),
OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify amount of times to repeat the run"),
OPT_END()
};
static const char * const bench_usage[] = {
"perf bench [<common options>] <collection> <benchmark> [<options>]",
NULL
};
static void print_usage(void)
{
struct collection *coll;
int i;
printf("Usage: \n");
for (i = 0; bench_usage[i]; i++)
printf("\t%s\n", bench_usage[i]);
printf("\n");
printf(" # List of all available benchmark collections:\n\n");
for_each_collection(coll)
printf("%14s: %s\n", coll->name, coll->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;
}
/*
* Run a specific benchmark but first rename the running task's ->comm[]
* to something meaningful:
*/
static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
int argc, const char **argv)
{
int size;
char *name;
int ret;
size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
name = zalloc(size);
BUG_ON(!name);
scnprintf(name, size, "%s-%s", coll_name, bench_name);
prctl(PR_SET_NAME, name);
argv[0] = name;
ret = fn(argc, argv);
free(name);
return ret;
}
static void run_collection(struct collection *coll)
{
struct bench *bench;
const char *argv[2];
argv[1] = NULL;
/*
* TODO:
*
* Preparing preset parameters for
* embedded, ordinary PC, HPC, etc...
* would be helpful.
*/
for_each_bench(coll, bench) {
if (!bench->fn)
break;
printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
fflush(stdout);
argv[1] = bench->name;
run_bench(coll->name, bench->name, bench->fn, 1, argv);
printf("\n");
}
}
static void run_all_collections(void)
{
struct collection *coll;
for_each_collection(coll)
run_collection(coll);
}
int cmd_bench(int argc, const char **argv)
{
struct collection *coll;
int ret = 0;
if (argc < 2) {
/* No collection 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 (bench_repeat == 0) {
printf("Invalid repeat option: Must specify a positive value\n");
goto end;
}
if (argc < 1) {
print_usage();
goto end;
}
if (!strcmp(argv[0], "all")) {
run_all_collections();
goto end;
}
for_each_collection(coll) {
struct bench *bench;
if (strcmp(coll->name, argv[0]))
continue;
if (argc < 2) {
/* No bench specified. */
dump_benchmarks(coll);
goto end;
}
if (!strcmp(argv[1], "all")) {
run_collection(coll);
goto end;
}
for_each_bench(coll, bench) {
if (strcmp(bench->name, argv[1]))
continue;
if (bench_format == BENCH_FORMAT_DEFAULT)
printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
fflush(stdout);
ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1);
goto end;
}
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
dump_benchmarks(coll);
goto end;
}
printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
ret = 1;
goto end;
}
printf("Unknown collection: '%s'\n", argv[0]);
ret = 1;
end:
return ret;
}