exynos-linux-stable/tools/perf/tests/builtin-test.c
Sandipan Das 2fc0fb0331 perf tests: Fix indexing when invoking subtests
[ Upstream commit aa90f9f9554616d5738f7bedb4a8f0e5e14d1bc6 ]

Recently, the subtest numbering was changed to start from 1.  While it
is fine for displaying results, this should not be the case when the
subtests are actually invoked.

Typically, the subtests are stored in zero-indexed arrays and invoked
based on the index passed to the main test function.  Since the index
now starts from 1, the second subtest in the array (index 1) gets
invoked instead of the first (index 0).  This applies to all of the
following subtests but for the last one, the subtest always fails
because it does not meet the boundary condition of the subtest index
being lesser than the number of subtests.

This can be observed on powerpc64 and x86_64 systems running Fedora 28
as shown below.

Before:

  # perf test "builtin clang support"
  55: builtin clang support                                 :
  55.1: builtin clang compile C source to IR                : Ok
  55.2: builtin clang compile C source to ELF object        : FAILED!

  # perf test "LLVM search and compile"
  38: LLVM search and compile                               :
  38.1: Basic BPF llvm compile                              : Ok
  38.2: kbuild searching                                    : Ok
  38.3: Compile source for BPF prologue generation          : Ok
  38.4: Compile source for BPF relocation                   : FAILED!

  # perf test "BPF filter"
  40: BPF filter                                            :
  40.1: Basic BPF filtering                                 : Ok
  40.2: BPF pinning                                         : Ok
  40.3: BPF prologue generation                             : Ok
  40.4: BPF relocation checker                              : FAILED!

After:

  # perf test "builtin clang support"
  55: builtin clang support                                 :
  55.1: builtin clang compile C source to IR                : Ok
  55.2: builtin clang compile C source to ELF object        : Ok

  # perf test "LLVM search and compile"
  38: LLVM search and compile                               :
  38.1: Basic BPF llvm compile                              : Ok
  38.2: kbuild searching                                    : Ok
  38.3: Compile source for BPF prologue generation          : Ok
  38.4: Compile source for BPF relocation                   : Ok

  # perf test "BPF filter"
  40: BPF filter                                            :
  40.1: Basic BPF filtering                                 : Ok
  40.2: BPF pinning                                         : Ok
  40.3: BPF prologue generation                             : Ok
  40.4: BPF relocation checker                              : Ok

Signed-off-by: Sandipan Das <sandipan@linux.ibm.com>
Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Hendrik Brueckner <brueckner@linux.ibm.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Cc: Thomas Richter <tmricht@linux.ibm.com>
Fixes: 9ef0112442bd ("perf test: Fix subtest number when showing results")
Link: http://lkml.kernel.org/r/20180726171733.33208-1-sandipan@linux.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2018-11-10 07:42:56 -08:00

479 lines
9.7 KiB
C

/*
* builtin-test.c
*
* Builtin regression testing command: ever growing number of sanity tests
*/
#include <unistd.h>
#include <string.h>
#include "builtin.h"
#include "hist.h"
#include "intlist.h"
#include "tests.h"
#include "debug.h"
#include "color.h"
#include <subcmd/parse-options.h>
#include "symbol.h"
static bool dont_fork;
struct test __weak arch_tests[] = {
{
.func = NULL,
},
};
static struct test generic_tests[] = {
{
.desc = "vmlinux symtab matches kallsyms",
.func = test__vmlinux_matches_kallsyms,
},
{
.desc = "detect openat syscall event",
.func = test__openat_syscall_event,
},
{
.desc = "detect openat syscall event on all cpus",
.func = test__openat_syscall_event_on_all_cpus,
},
{
.desc = "read samples using the mmap interface",
.func = test__basic_mmap,
},
{
.desc = "parse events tests",
.func = test__parse_events,
},
{
.desc = "Validate PERF_RECORD_* events & perf_sample fields",
.func = test__PERF_RECORD,
},
{
.desc = "Test perf pmu format parsing",
.func = test__pmu,
},
{
.desc = "Test dso data read",
.func = test__dso_data,
},
{
.desc = "Test dso data cache",
.func = test__dso_data_cache,
},
{
.desc = "Test dso data reopen",
.func = test__dso_data_reopen,
},
{
.desc = "roundtrip evsel->name check",
.func = test__perf_evsel__roundtrip_name_test,
},
{
.desc = "Check parsing of sched tracepoints fields",
.func = test__perf_evsel__tp_sched_test,
},
{
.desc = "Generate and check syscalls:sys_enter_openat event fields",
.func = test__syscall_openat_tp_fields,
},
{
.desc = "struct perf_event_attr setup",
.func = test__attr,
},
{
.desc = "Test matching and linking multiple hists",
.func = test__hists_link,
},
{
.desc = "Try 'import perf' in python, checking link problems",
.func = test__python_use,
},
{
.desc = "Test breakpoint overflow signal handler",
.func = test__bp_signal,
},
{
.desc = "Test breakpoint overflow sampling",
.func = test__bp_signal_overflow,
},
{
.desc = "Test number of exit event of a simple workload",
.func = test__task_exit,
},
{
.desc = "Test software clock events have valid period values",
.func = test__sw_clock_freq,
},
{
.desc = "Test object code reading",
.func = test__code_reading,
},
{
.desc = "Test sample parsing",
.func = test__sample_parsing,
},
{
.desc = "Test using a dummy software event to keep tracking",
.func = test__keep_tracking,
},
{
.desc = "Test parsing with no sample_id_all bit set",
.func = test__parse_no_sample_id_all,
},
{
.desc = "Test filtering hist entries",
.func = test__hists_filter,
},
{
.desc = "Test mmap thread lookup",
.func = test__mmap_thread_lookup,
},
{
.desc = "Test thread mg sharing",
.func = test__thread_mg_share,
},
{
.desc = "Test output sorting of hist entries",
.func = test__hists_output,
},
{
.desc = "Test cumulation of child hist entries",
.func = test__hists_cumulate,
},
{
.desc = "Test tracking with sched_switch",
.func = test__switch_tracking,
},
{
.desc = "Filter fds with revents mask in a fdarray",
.func = test__fdarray__filter,
},
{
.desc = "Add fd to a fdarray, making it autogrow",
.func = test__fdarray__add,
},
{
.desc = "Test kmod_path__parse function",
.func = test__kmod_path__parse,
},
{
.desc = "Test thread map",
.func = test__thread_map,
},
{
.desc = "Test LLVM searching and compiling",
.func = test__llvm,
.subtest = {
.skip_if_fail = true,
.get_nr = test__llvm_subtest_get_nr,
.get_desc = test__llvm_subtest_get_desc,
},
},
{
.desc = "Test topology in session",
.func = test_session_topology,
},
{
.desc = "Test BPF filter",
.func = test__bpf,
.subtest = {
.skip_if_fail = true,
.get_nr = test__bpf_subtest_get_nr,
.get_desc = test__bpf_subtest_get_desc,
},
},
{
.desc = "Test thread map synthesize",
.func = test__thread_map_synthesize,
},
{
.desc = "Test cpu map synthesize",
.func = test__cpu_map_synthesize,
},
{
.desc = "Test stat config synthesize",
.func = test__synthesize_stat_config,
},
{
.desc = "Test stat synthesize",
.func = test__synthesize_stat,
},
{
.desc = "Test stat round synthesize",
.func = test__synthesize_stat_round,
},
{
.desc = "Test attr update synthesize",
.func = test__event_update,
},
{
.desc = "Test events times",
.func = test__event_times,
},
{
.desc = "Test backward reading from ring buffer",
.func = test__backward_ring_buffer,
},
{
.desc = "Test cpu map print",
.func = test__cpu_map_print,
},
{
.desc = "Test SDT event probing",
.func = test__sdt_event,
},
{
.desc = "Test is_printable_array function",
.func = test__is_printable_array,
},
{
.desc = "Test bitmap print",
.func = test__bitmap_print,
},
{
.func = NULL,
},
};
static struct test *tests[] = {
generic_tests,
arch_tests,
};
static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[])
{
int i;
if (argc == 0)
return true;
for (i = 0; i < argc; ++i) {
char *end;
long nr = strtoul(argv[i], &end, 10);
if (*end == '\0') {
if (nr == curr + 1)
return true;
continue;
}
if (strcasestr(test->desc, argv[i]))
return true;
}
return false;
}
static int run_test(struct test *test, int subtest)
{
int status, err = -1, child = dont_fork ? 0 : fork();
char sbuf[STRERR_BUFSIZE];
if (child < 0) {
pr_err("failed to fork test: %s\n",
str_error_r(errno, sbuf, sizeof(sbuf)));
return -1;
}
if (!child) {
if (!dont_fork) {
pr_debug("test child forked, pid %d\n", getpid());
if (!verbose) {
int nullfd = open("/dev/null", O_WRONLY);
if (nullfd >= 0) {
close(STDERR_FILENO);
close(STDOUT_FILENO);
dup2(nullfd, STDOUT_FILENO);
dup2(STDOUT_FILENO, STDERR_FILENO);
close(nullfd);
}
} else {
signal(SIGSEGV, sighandler_dump_stack);
signal(SIGFPE, sighandler_dump_stack);
}
}
err = test->func(subtest);
if (!dont_fork)
exit(err);
}
if (!dont_fork) {
wait(&status);
if (WIFEXITED(status)) {
err = (signed char)WEXITSTATUS(status);
pr_debug("test child finished with %d\n", err);
} else if (WIFSIGNALED(status)) {
err = -1;
pr_debug("test child interrupted\n");
}
}
return err;
}
#define for_each_test(j, t) \
for (j = 0; j < ARRAY_SIZE(tests); j++) \
for (t = &tests[j][0]; t->func; t++)
static int test_and_print(struct test *t, bool force_skip, int subtest)
{
int err;
if (!force_skip) {
pr_debug("\n--- start ---\n");
err = run_test(t, subtest);
pr_debug("---- end ----\n");
} else {
pr_debug("\n--- force skipped ---\n");
err = TEST_SKIP;
}
if (!t->subtest.get_nr)
pr_debug("%s:", t->desc);
else
pr_debug("%s subtest %d:", t->desc, subtest + 1);
switch (err) {
case TEST_OK:
pr_info(" Ok\n");
break;
case TEST_SKIP:
color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
break;
case TEST_FAIL:
default:
color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
break;
}
return err;
}
static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
{
struct test *t;
unsigned int j;
int i = 0;
int width = 0;
for_each_test(j, t) {
int len = strlen(t->desc);
if (width < len)
width = len;
}
for_each_test(j, t) {
int curr = i++, err;
if (!perf_test__matches(t, curr, argc, argv))
continue;
pr_info("%2d: %-*s:", i, width, t->desc);
if (intlist__find(skiplist, i)) {
color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
continue;
}
if (!t->subtest.get_nr) {
test_and_print(t, false, -1);
} else {
int subn = t->subtest.get_nr();
/*
* minus 2 to align with normal testcases.
* For subtest we print additional '.x' in number.
* for example:
*
* 35: Test LLVM searching and compiling :
* 35.1: Basic BPF llvm compiling test : Ok
*/
int subw = width > 2 ? width - 2 : width;
bool skip = false;
int subi;
if (subn <= 0) {
color_fprintf(stderr, PERF_COLOR_YELLOW,
" Skip (not compiled in)\n");
continue;
}
pr_info("\n");
for (subi = 0; subi < subn; subi++) {
int len = strlen(t->subtest.get_desc(subi));
if (subw < len)
subw = len;
}
for (subi = 0; subi < subn; subi++) {
pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
t->subtest.get_desc(subi));
err = test_and_print(t, skip, subi);
if (err != TEST_OK && t->subtest.skip_if_fail)
skip = true;
}
}
}
return 0;
}
static int perf_test__list(int argc, const char **argv)
{
unsigned int j;
struct test *t;
int i = 0;
for_each_test(j, t) {
if (argc > 1 && !strstr(t->desc, argv[1]))
continue;
pr_info("%2d: %s\n", ++i, t->desc);
}
return 0;
}
int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
{
const char *test_usage[] = {
"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
NULL,
};
const char *skip = NULL;
const struct option test_options[] = {
OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show symbol address, etc)"),
OPT_BOOLEAN('F', "dont-fork", &dont_fork,
"Do not fork for testcase"),
OPT_END()
};
const char * const test_subcommands[] = { "list", NULL };
struct intlist *skiplist = NULL;
int ret = hists__init();
if (ret < 0)
return ret;
argc = parse_options_subcommand(argc, argv, test_options, test_subcommands, test_usage, 0);
if (argc >= 1 && !strcmp(argv[0], "list"))
return perf_test__list(argc, argv);
symbol_conf.priv_size = sizeof(int);
symbol_conf.sort_by_name = true;
symbol_conf.try_vmlinux_path = true;
if (symbol__init(NULL) < 0)
return -1;
if (skip != NULL)
skiplist = intlist__new(skip);
return __cmd_test(argc, argv, skiplist);
}