2009-11-05 03:31:34 +03:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* builtin-bench.c
|
|
|
|
*
|
|
|
|
* General benchmarking subsystem provided by perf
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Available subsystem list:
|
|
|
|
* sched ... scheduler and IPC mechanism
|
2009-11-17 18:20:09 +03:00
|
|
|
* mem ... memory access performance
|
2009-11-05 03:31:34 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "perf.h"
|
|
|
|
#include "util/util.h"
|
|
|
|
#include "util/parse-options.h"
|
|
|
|
#include "builtin.h"
|
|
|
|
#include "bench/bench.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
struct bench_suite {
|
|
|
|
const char *name;
|
|
|
|
const char *summary;
|
|
|
|
int (*fn)(int, const char **, const char *);
|
|
|
|
};
|
2009-12-13 11:01:59 +03:00
|
|
|
\
|
|
|
|
/* sentinel: easy for help */
|
2012-06-20 10:08:06 +04:00
|
|
|
#define suite_all { "all", "Test all benchmark suites", NULL }
|
2009-11-05 03:31:34 +03:00
|
|
|
|
perf: Add 'perf bench numa mem' NUMA performance measurement suite
Add a suite of NUMA performance benchmarks.
The goal was simulate the behavior and access patterns of real NUMA
workloads, via a wide range of parameters, so this tool goes well
beyond simple bzero() measurements that most NUMA micro-benchmarks use:
- It processes the data and creates a chain of data dependencies,
like a real workload would. Neither the compiler, nor the
kernel (via KSM and other optimizations) nor the CPU can
eliminate parts of the workload.
- It randomizes the initial state and also randomizes the target
addresses of the processing - it's not a simple forward scan
of addresses.
- It provides flexible options to set process, thread and memory
relationship information: -G sets "global" memory shared between
all test processes, -P sets "process" memory shared by all
threads of a process and -T sets "thread" private memory.
- There's a NUMA convergence monitoring and convergence latency
measurement option via -c and -m.
- Micro-sleeps and synchronization can be injected to provoke lock
contention and scheduling, via the -u and -S options. This simulates
IO and contention.
- The -x option instructs the workload to 'perturb' itself artificially
every N seconds, by moving to the first and last CPU of the system
periodically. This way the stability of convergence equilibrium and
the number of steps taken for the scheduler to reach equilibrium again
can be measured.
- The amount of work can be specified via the -l loop count, and/or
via a -s seconds-timeout value.
- CPU and node memory binding options, to test hard binding scenarios.
THP can be turned on and off via madvise() calls.
- Live reporting of convergence progress in an 'at glance' output format.
Printing of convergence and deconvergence events.
The 'perf bench numa mem -a' option will start an array of about 30
individual tests that will each output such measurements:
# Running 5x5-bw-thread, "perf bench numa mem -p 5 -t 5 -P 512 -s 20 -zZ0q --thp 1"
5x5-bw-thread, 20.276, secs, runtime-max/thread
5x5-bw-thread, 20.004, secs, runtime-min/thread
5x5-bw-thread, 20.155, secs, runtime-avg/thread
5x5-bw-thread, 0.671, %, spread-runtime/thread
5x5-bw-thread, 21.153, GB, data/thread
5x5-bw-thread, 528.818, GB, data-total
5x5-bw-thread, 0.959, nsecs, runtime/byte/thread
5x5-bw-thread, 1.043, GB/sec, thread-speed
5x5-bw-thread, 26.081, GB/sec, total-speed
See the help text and the code for more details.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-12-06 16:51:59 +04:00
|
|
|
static struct bench_suite numa_suites[] = {
|
|
|
|
{ "mem",
|
|
|
|
"Benchmark for NUMA workloads",
|
|
|
|
bench_numa },
|
|
|
|
suite_all,
|
|
|
|
{ NULL,
|
|
|
|
NULL,
|
|
|
|
NULL }
|
|
|
|
};
|
|
|
|
|
2009-11-05 03:31:34 +03:00
|
|
|
static struct bench_suite sched_suites[] = {
|
|
|
|
{ "messaging",
|
|
|
|
"Benchmark for scheduler and IPC mechanisms",
|
|
|
|
bench_sched_messaging },
|
|
|
|
{ "pipe",
|
|
|
|
"Flood of communication over pipe() between two processes",
|
|
|
|
bench_sched_pipe },
|
2009-12-13 11:01:59 +03:00
|
|
|
suite_all,
|
2009-11-05 03:31:34 +03:00
|
|
|
{ NULL,
|
|
|
|
NULL,
|
|
|
|
NULL }
|
|
|
|
};
|
|
|
|
|
2009-11-17 18:20:09 +03:00
|
|
|
static struct bench_suite mem_suites[] = {
|
|
|
|
{ "memcpy",
|
|
|
|
"Simple memory copy in various ways",
|
|
|
|
bench_mem_memcpy },
|
2012-01-24 16:03:22 +04:00
|
|
|
{ "memset",
|
|
|
|
"Simple memory set in various ways",
|
|
|
|
bench_mem_memset },
|
2009-12-13 11:01:59 +03:00
|
|
|
suite_all,
|
2009-11-17 18:20:09 +03:00
|
|
|
{ NULL,
|
|
|
|
NULL,
|
|
|
|
NULL }
|
|
|
|
};
|
|
|
|
|
2009-11-05 03:31:34 +03:00
|
|
|
struct bench_subsys {
|
|
|
|
const char *name;
|
|
|
|
const char *summary;
|
|
|
|
struct bench_suite *suites;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct bench_subsys subsystems[] = {
|
perf: Add 'perf bench numa mem' NUMA performance measurement suite
Add a suite of NUMA performance benchmarks.
The goal was simulate the behavior and access patterns of real NUMA
workloads, via a wide range of parameters, so this tool goes well
beyond simple bzero() measurements that most NUMA micro-benchmarks use:
- It processes the data and creates a chain of data dependencies,
like a real workload would. Neither the compiler, nor the
kernel (via KSM and other optimizations) nor the CPU can
eliminate parts of the workload.
- It randomizes the initial state and also randomizes the target
addresses of the processing - it's not a simple forward scan
of addresses.
- It provides flexible options to set process, thread and memory
relationship information: -G sets "global" memory shared between
all test processes, -P sets "process" memory shared by all
threads of a process and -T sets "thread" private memory.
- There's a NUMA convergence monitoring and convergence latency
measurement option via -c and -m.
- Micro-sleeps and synchronization can be injected to provoke lock
contention and scheduling, via the -u and -S options. This simulates
IO and contention.
- The -x option instructs the workload to 'perturb' itself artificially
every N seconds, by moving to the first and last CPU of the system
periodically. This way the stability of convergence equilibrium and
the number of steps taken for the scheduler to reach equilibrium again
can be measured.
- The amount of work can be specified via the -l loop count, and/or
via a -s seconds-timeout value.
- CPU and node memory binding options, to test hard binding scenarios.
THP can be turned on and off via madvise() calls.
- Live reporting of convergence progress in an 'at glance' output format.
Printing of convergence and deconvergence events.
The 'perf bench numa mem -a' option will start an array of about 30
individual tests that will each output such measurements:
# Running 5x5-bw-thread, "perf bench numa mem -p 5 -t 5 -P 512 -s 20 -zZ0q --thp 1"
5x5-bw-thread, 20.276, secs, runtime-max/thread
5x5-bw-thread, 20.004, secs, runtime-min/thread
5x5-bw-thread, 20.155, secs, runtime-avg/thread
5x5-bw-thread, 0.671, %, spread-runtime/thread
5x5-bw-thread, 21.153, GB, data/thread
5x5-bw-thread, 528.818, GB, data-total
5x5-bw-thread, 0.959, nsecs, runtime/byte/thread
5x5-bw-thread, 1.043, GB/sec, thread-speed
5x5-bw-thread, 26.081, GB/sec, total-speed
See the help text and the code for more details.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-12-06 16:51:59 +04:00
|
|
|
{ "numa",
|
|
|
|
"NUMA scheduling and MM behavior",
|
|
|
|
numa_suites },
|
2009-11-05 03:31:34 +03:00
|
|
|
{ "sched",
|
|
|
|
"scheduler and IPC mechanism",
|
|
|
|
sched_suites },
|
2009-11-17 18:20:09 +03:00
|
|
|
{ "mem",
|
|
|
|
"memory access performance",
|
|
|
|
mem_suites },
|
2009-12-13 11:01:59 +03:00
|
|
|
{ "all", /* sentinel: easy for help */
|
2012-06-20 10:08:06 +04:00
|
|
|
"all benchmark subsystem",
|
2009-12-13 11:01:59 +03:00
|
|
|
NULL },
|
2009-11-05 03:31:34 +03:00
|
|
|
{ NULL,
|
|
|
|
NULL,
|
2009-11-17 18:20:09 +03:00
|
|
|
NULL }
|
2009-11-05 03:31:34 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
static void dump_suites(int subsys_index)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2009-12-13 11:01:59 +03:00
|
|
|
printf("# List of available suites for %s...\n\n",
|
2009-11-05 03:31:34 +03:00
|
|
|
subsystems[subsys_index].name);
|
|
|
|
|
|
|
|
for (i = 0; subsystems[subsys_index].suites[i].name; i++)
|
2009-12-13 11:01:59 +03:00
|
|
|
printf("%14s: %s\n",
|
2009-11-05 03:31:34 +03:00
|
|
|
subsystems[subsys_index].suites[i].name,
|
|
|
|
subsystems[subsys_index].suites[i].summary);
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-17 23:22:41 +04:00
|
|
|
static const char *bench_format_str;
|
2009-11-10 02:20:00 +03:00
|
|
|
int bench_format = BENCH_FORMAT_DEFAULT;
|
|
|
|
|
|
|
|
static const struct option bench_options[] = {
|
|
|
|
OPT_STRING('f', "format", &bench_format_str, "default",
|
|
|
|
"Specify format style"),
|
|
|
|
OPT_END()
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char * const bench_usage[] = {
|
|
|
|
"perf bench [<common options>] <subsystem> <suite> [<options>]",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static void print_usage(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printf("Usage: \n");
|
|
|
|
for (i = 0; bench_usage[i]; i++)
|
|
|
|
printf("\t%s\n", bench_usage[i]);
|
|
|
|
printf("\n");
|
|
|
|
|
2009-12-13 11:01:59 +03:00
|
|
|
printf("# List of available subsystems...\n\n");
|
2009-11-10 02:20:00 +03:00
|
|
|
|
|
|
|
for (i = 0; subsystems[i].name; i++)
|
2009-12-13 11:01:59 +03:00
|
|
|
printf("%14s: %s\n",
|
2009-11-10 02:20:00 +03:00
|
|
|
subsystems[i].name, subsystems[i].summary);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2010-05-17 23:22:41 +04:00
|
|
|
static int bench_str2int(const char *str)
|
2009-11-10 02:20:00 +03:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-12-13 11:01:59 +03:00
|
|
|
static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const char *argv[2];
|
|
|
|
struct bench_suite *suites = subsys->suites;
|
|
|
|
|
|
|
|
argv[1] = NULL;
|
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* preparing preset parameters for
|
|
|
|
* embedded, ordinary PC, HPC, etc...
|
|
|
|
* will be helpful
|
|
|
|
*/
|
|
|
|
for (i = 0; suites[i].fn; i++) {
|
|
|
|
printf("# Running %s/%s benchmark...\n",
|
|
|
|
subsys->name,
|
|
|
|
suites[i].name);
|
2013-01-08 13:39:26 +04:00
|
|
|
fflush(stdout);
|
2009-12-13 11:01:59 +03:00
|
|
|
|
|
|
|
argv[1] = suites[i].name;
|
|
|
|
suites[i].fn(1, argv, NULL);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void all_subsystem(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; subsystems[i].suites; i++)
|
|
|
|
all_suite(&subsystems[i]);
|
|
|
|
}
|
|
|
|
|
2012-09-11 02:15:03 +04:00
|
|
|
int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
|
2009-11-05 03:31:34 +03:00
|
|
|
{
|
|
|
|
int i, j, status = 0;
|
|
|
|
|
|
|
|
if (argc < 2) {
|
|
|
|
/* No subsystem specified. */
|
2009-11-10 02:20:00 +03:00
|
|
|
print_usage();
|
|
|
|
goto end;
|
|
|
|
}
|
2009-11-05 03:31:34 +03:00
|
|
|
|
2009-11-10 02:20:00 +03:00
|
|
|
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;
|
|
|
|
}
|
2009-11-05 03:31:34 +03:00
|
|
|
|
2009-11-10 02:20:00 +03:00
|
|
|
if (argc < 1) {
|
|
|
|
print_usage();
|
2009-11-05 03:31:34 +03:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2009-12-13 11:01:59 +03:00
|
|
|
if (!strcmp(argv[0], "all")) {
|
|
|
|
all_subsystem();
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2009-11-05 03:31:34 +03:00
|
|
|
for (i = 0; subsystems[i].name; i++) {
|
2009-11-10 02:20:00 +03:00
|
|
|
if (strcmp(subsystems[i].name, argv[0]))
|
2009-11-05 03:31:34 +03:00
|
|
|
continue;
|
|
|
|
|
2009-11-10 02:20:00 +03:00
|
|
|
if (argc < 2) {
|
2009-11-05 03:31:34 +03:00
|
|
|
/* No suite specified. */
|
|
|
|
dump_suites(i);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2009-12-13 11:01:59 +03:00
|
|
|
if (!strcmp(argv[1], "all")) {
|
|
|
|
all_suite(&subsystems[i]);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2009-11-05 03:31:34 +03:00
|
|
|
for (j = 0; subsystems[i].suites[j].name; j++) {
|
2009-11-10 02:20:00 +03:00
|
|
|
if (strcmp(subsystems[i].suites[j].name, argv[1]))
|
2009-11-05 03:31:34 +03:00
|
|
|
continue;
|
|
|
|
|
2009-11-10 18:04:00 +03:00
|
|
|
if (bench_format == BENCH_FORMAT_DEFAULT)
|
|
|
|
printf("# Running %s/%s benchmark...\n",
|
|
|
|
subsystems[i].name,
|
|
|
|
subsystems[i].suites[j].name);
|
2013-01-08 13:39:26 +04:00
|
|
|
fflush(stdout);
|
2009-11-10 02:20:00 +03:00
|
|
|
status = subsystems[i].suites[j].fn(argc - 1,
|
|
|
|
argv + 1, prefix);
|
2009-11-05 03:31:34 +03:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2009-11-10 02:20:00 +03:00
|
|
|
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
|
2009-11-05 03:31:34 +03:00
|
|
|
dump_suites(i);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2009-11-10 02:20:00 +03:00
|
|
|
printf("Unknown suite:%s for %s\n", argv[1], argv[0]);
|
2009-11-05 03:31:34 +03:00
|
|
|
status = 1;
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2009-11-10 02:20:00 +03:00
|
|
|
printf("Unknown subsystem:%s\n", argv[0]);
|
2009-11-05 03:31:34 +03:00
|
|
|
status = 1;
|
|
|
|
|
|
|
|
end:
|
|
|
|
return status;
|
|
|
|
}
|