perf tools: Add automated tests for events parsing
Adding builtin test for parse_events function, which is responsible for parsing/processing "-e" option for stat/top/record commands. This new test will run within the builtin test command suite (perf test). One or several tests were added for each type of event. More tests could be added easily if needed. Signed-off-by: Jiri Olsa <jolsa@redhat.com> Cc: acme@redhat.com Cc: a.p.zijlstra@chello.nl Cc: paulus@samba.org Link: http://lkml.kernel.org/r/1310635534-4013-3-git-send-email-jolsa@redhat.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Родитель
f120f9d51b
Коммит
13b62567e9
|
@ -12,6 +12,7 @@
|
|||
#include "util/parse-events.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/thread_map.h"
|
||||
#include "../../include/linux/hw_breakpoint.h"
|
||||
|
||||
static long page_size;
|
||||
|
||||
|
@ -600,6 +601,246 @@ out_free_threads:
|
|||
#undef nsyscalls
|
||||
}
|
||||
|
||||
#define TEST_ASSERT_VAL(text, cond) \
|
||||
do { \
|
||||
if (!cond) { \
|
||||
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int test__checkevent_tracepoint(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong sample_type",
|
||||
(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
|
||||
evsel->attr.sample_type);
|
||||
TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
|
||||
|
||||
list_for_each_entry(evsel, &evlist->entries, node) {
|
||||
TEST_ASSERT_VAL("wrong type",
|
||||
PERF_TYPE_TRACEPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong sample_type",
|
||||
(PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
|
||||
== evsel->attr.sample_type);
|
||||
TEST_ASSERT_VAL("wrong sample_period",
|
||||
1 == evsel->attr.sample_period);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_raw(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_numeric(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config",
|
||||
PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config",
|
||||
PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_genhw(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_breakpoint(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
|
||||
TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
|
||||
evsel->attr.bp_type);
|
||||
TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
|
||||
evsel->attr.bp_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
|
||||
TEST_ASSERT_VAL("wrong bp_type",
|
||||
HW_BREAKPOINT_X == evsel->attr.bp_type);
|
||||
TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type",
|
||||
PERF_TYPE_BREAKPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
|
||||
TEST_ASSERT_VAL("wrong bp_type",
|
||||
HW_BREAKPOINT_R == evsel->attr.bp_type);
|
||||
TEST_ASSERT_VAL("wrong bp_len",
|
||||
HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
|
||||
{
|
||||
struct perf_evsel *evsel = list_entry(evlist->entries.next,
|
||||
struct perf_evsel, node);
|
||||
|
||||
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
|
||||
TEST_ASSERT_VAL("wrong type",
|
||||
PERF_TYPE_BREAKPOINT == evsel->attr.type);
|
||||
TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
|
||||
TEST_ASSERT_VAL("wrong bp_type",
|
||||
HW_BREAKPOINT_W == evsel->attr.bp_type);
|
||||
TEST_ASSERT_VAL("wrong bp_len",
|
||||
HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct test__event_st {
|
||||
const char *name;
|
||||
__u32 type;
|
||||
int (*check)(struct perf_evlist *evlist);
|
||||
} test__events[] = {
|
||||
{
|
||||
.name = "syscalls:sys_enter_open",
|
||||
.check = test__checkevent_tracepoint,
|
||||
},
|
||||
{
|
||||
.name = "syscalls:*",
|
||||
.check = test__checkevent_tracepoint_multi,
|
||||
},
|
||||
{
|
||||
.name = "r1",
|
||||
.check = test__checkevent_raw,
|
||||
},
|
||||
{
|
||||
.name = "1:1",
|
||||
.check = test__checkevent_numeric,
|
||||
},
|
||||
{
|
||||
.name = "instructions",
|
||||
.check = test__checkevent_symbolic_name,
|
||||
},
|
||||
{
|
||||
.name = "faults",
|
||||
.check = test__checkevent_symbolic_alias,
|
||||
},
|
||||
{
|
||||
.name = "L1-dcache-load-miss",
|
||||
.check = test__checkevent_genhw,
|
||||
},
|
||||
{
|
||||
.name = "mem:0",
|
||||
.check = test__checkevent_breakpoint,
|
||||
},
|
||||
{
|
||||
.name = "mem:0:x",
|
||||
.check = test__checkevent_breakpoint_x,
|
||||
},
|
||||
{
|
||||
.name = "mem:0:r",
|
||||
.check = test__checkevent_breakpoint_r,
|
||||
},
|
||||
{
|
||||
.name = "mem:0:w",
|
||||
.check = test__checkevent_breakpoint_w,
|
||||
},
|
||||
};
|
||||
|
||||
#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
|
||||
|
||||
static int test__parse_events(void)
|
||||
{
|
||||
struct perf_evlist *evlist;
|
||||
u_int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < TEST__EVENTS_CNT; i++) {
|
||||
struct test__event_st *e = &test__events[i];
|
||||
|
||||
evlist = perf_evlist__new(NULL, NULL);
|
||||
if (evlist == NULL)
|
||||
break;
|
||||
|
||||
ret = parse_events(evlist, e->name, 0);
|
||||
if (ret) {
|
||||
pr_debug("failed to parse event '%s', err %d\n",
|
||||
e->name, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = e->check(evlist);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
perf_evlist__delete(evlist);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static struct test {
|
||||
const char *desc;
|
||||
int (*func)(void);
|
||||
|
@ -620,6 +861,10 @@ static struct test {
|
|||
.desc = "read samples using the mmap interface",
|
||||
.func = test__basic_mmap,
|
||||
},
|
||||
{
|
||||
.desc = "parse events tests",
|
||||
.func = test__parse_events,
|
||||
},
|
||||
{
|
||||
.func = NULL,
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче