From f50246e2e2e33aacc68ac3ec41cf2d6a08860bc4 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 21 May 2012 09:12:49 +0200 Subject: perf test: Move parse event automated tests to separated object Moving event parsing specific tests into separated file: util/parse-events-test.c Also changing the code a bit to ease running separate tests. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337584373-2741-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 1 + tools/perf/builtin-test.c | 552 +-------------------------------- tools/perf/util/parse-events-test.c | 600 ++++++++++++++++++++++++++++++++++++ tools/perf/util/parse-events.h | 3 + 4 files changed, 605 insertions(+), 551 deletions(-) create mode 100644 tools/perf/util/parse-events-test.c (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index fa37cd53e9b9..91840e171815 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -332,6 +332,7 @@ LIB_OBJS += $(OUTPUT)util/help.o LIB_OBJS += $(OUTPUT)util/levenshtein.o LIB_OBJS += $(OUTPUT)util/parse-options.o LIB_OBJS += $(OUTPUT)util/parse-events.o +LIB_OBJS += $(OUTPUT)util/parse-events-test.o LIB_OBJS += $(OUTPUT)util/path.o LIB_OBJS += $(OUTPUT)util/rbtree.o LIB_OBJS += $(OUTPUT)util/bitmap.o diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 6c47376e29d8..5a8727c08757 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -604,556 +604,6 @@ 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", 0x1a == 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_name_config(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_CPU_CYCLES == evsel->attr.config); - TEST_ASSERT_VAL("wrong period", - 100000 == evsel->attr.sample_period); - TEST_ASSERT_VAL("wrong config1", - 0 == evsel->attr.config1); - TEST_ASSERT_VAL("wrong config2", - 1 == evsel->attr.config2); - 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 int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_tracepoint(evlist); -} - -static int -test__checkevent_tracepoint_multi_modifier(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 exclude_user", - !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - } - - return test__checkevent_tracepoint_multi(evlist); -} - -static int test__checkevent_raw_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_raw(evlist); -} - -static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_numeric(evlist); -} - -static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_symbolic_name(evlist); -} - -static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); - - return test__checkevent_symbolic_name(evlist); -} - -static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); - TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); - - return test__checkevent_symbolic_name(evlist); -} - -static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_symbolic_alias(evlist); -} - -static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_genhw(evlist); -} - -static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_breakpoint(evlist); -} - -static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_breakpoint_x(evlist); -} - -static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_breakpoint_r(evlist); -} - -static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_breakpoint_w(evlist); -} - -static int test__checkevent_pmu(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", 10 == evsel->attr.config); - TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1); - TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2); - TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period); - - return 0; -} - -static int test__checkevent_list(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); - - /* r1 */ - evsel = list_entry(evlist->entries.next, struct perf_evsel, node); - TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); - TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); - TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2); - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - /* syscalls:sys_enter_open:k */ - evsel = list_entry(evsel->node.next, struct perf_evsel, 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); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - /* 1:1:hp */ - evsel = list_entry(evsel->node.next, struct perf_evsel, node); - TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); - TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - 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 = "r1a", - .check = test__checkevent_raw, - }, - { - .name = "1:1", - .check = test__checkevent_numeric, - }, - { - .name = "instructions", - .check = test__checkevent_symbolic_name, - }, - { - .name = "cycles/period=100000,config2/", - .check = test__checkevent_symbolic_name_config, - }, - { - .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, - }, - { - .name = "syscalls:sys_enter_open:k", - .check = test__checkevent_tracepoint_modifier, - }, - { - .name = "syscalls:*:u", - .check = test__checkevent_tracepoint_multi_modifier, - }, - { - .name = "r1a:kp", - .check = test__checkevent_raw_modifier, - }, - { - .name = "1:1:hp", - .check = test__checkevent_numeric_modifier, - }, - { - .name = "instructions:h", - .check = test__checkevent_symbolic_name_modifier, - }, - { - .name = "faults:u", - .check = test__checkevent_symbolic_alias_modifier, - }, - { - .name = "L1-dcache-load-miss:kp", - .check = test__checkevent_genhw_modifier, - }, - { - .name = "mem:0:u", - .check = test__checkevent_breakpoint_modifier, - }, - { - .name = "mem:0:x:k", - .check = test__checkevent_breakpoint_x_modifier, - }, - { - .name = "mem:0:r:hp", - .check = test__checkevent_breakpoint_r_modifier, - }, - { - .name = "mem:0:w:up", - .check = test__checkevent_breakpoint_w_modifier, - }, - { - .name = "cpu/config=10,config1,config2=3,period=1000/u", - .check = test__checkevent_pmu, - }, - { - .name = "r1,syscalls:sys_enter_open:k,1:1:hp", - .check = test__checkevent_list, - }, - { - .name = "instructions:G", - .check = test__checkevent_exclude_host_modifier, - }, - { - .name = "instructions:H", - .check = test__checkevent_exclude_guest_modifier, - }, -}; - -#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); - perf_evlist__delete(evlist); - if (ret) - break; - } - - return ret; -} - static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, size_t *sizep) { @@ -1675,7 +1125,7 @@ static struct test { }, { .desc = "parse events tests", - .func = test__parse_events, + .func = parse_events__test, }, #if defined(__x86_64__) || defined(__i386__) { diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c new file mode 100644 index 000000000000..2e8f435384a6 --- /dev/null +++ b/tools/perf/util/parse-events-test.c @@ -0,0 +1,600 @@ + +#include "parse-events.h" +#include "evsel.h" +#include "evlist.h" +#include "sysfs.h" +#include "../../../include/linux/hw_breakpoint.h" + +#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", 0x1a == 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_name_config(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_CPU_CYCLES == evsel->attr.config); + TEST_ASSERT_VAL("wrong period", + 100000 == evsel->attr.sample_period); + TEST_ASSERT_VAL("wrong config1", + 0 == evsel->attr.config1); + TEST_ASSERT_VAL("wrong config2", + 1 == evsel->attr.config2); + 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 int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_tracepoint(evlist); +} + +static int +test__checkevent_tracepoint_multi_modifier(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 exclude_user", + !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", + evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + } + + return test__checkevent_tracepoint_multi(evlist); +} + +static int test__checkevent_raw_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_raw(evlist); +} + +static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_numeric(evlist); +} + +static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); + + return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); + TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); + + return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_symbolic_alias(evlist); +} + +static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_genhw(evlist); +} + +static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_breakpoint(evlist); +} + +static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + return test__checkevent_breakpoint_x(evlist); +} + +static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_breakpoint_r(evlist); +} + +static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = list_entry(evlist->entries.next, + struct perf_evsel, node); + + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return test__checkevent_breakpoint_w(evlist); +} + +static int test__checkevent_pmu(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", 10 == evsel->attr.config); + TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1); + TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2); + TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period); + + return 0; +} + +static int test__checkevent_list(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries); + + /* r1 */ + evsel = list_entry(evlist->entries.next, struct perf_evsel, node); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); + TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1); + TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2); + TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + /* syscalls:sys_enter_open:k */ + evsel = list_entry(evsel->node.next, struct perf_evsel, 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); + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); + + /* 1:1:hp */ + evsel = list_entry(evsel->node.next, struct perf_evsel, node); + TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); + TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); + TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); + TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); + TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); + + return 0; +} + +struct test__event_st { + const char *name; + __u32 type; + int (*check)(struct perf_evlist *evlist); +}; + +static struct test__event_st test__events[] = { + [0] = { + .name = "syscalls:sys_enter_open", + .check = test__checkevent_tracepoint, + }, + [1] = { + .name = "syscalls:*", + .check = test__checkevent_tracepoint_multi, + }, + [2] = { + .name = "r1a", + .check = test__checkevent_raw, + }, + [3] = { + .name = "1:1", + .check = test__checkevent_numeric, + }, + [4] = { + .name = "instructions", + .check = test__checkevent_symbolic_name, + }, + [5] = { + .name = "cycles/period=100000,config2/", + .check = test__checkevent_symbolic_name_config, + }, + [6] = { + .name = "faults", + .check = test__checkevent_symbolic_alias, + }, + [7] = { + .name = "L1-dcache-load-miss", + .check = test__checkevent_genhw, + }, + [8] = { + .name = "mem:0", + .check = test__checkevent_breakpoint, + }, + [9] = { + .name = "mem:0:x", + .check = test__checkevent_breakpoint_x, + }, + [10] = { + .name = "mem:0:r", + .check = test__checkevent_breakpoint_r, + }, + [11] = { + .name = "mem:0:w", + .check = test__checkevent_breakpoint_w, + }, + [12] = { + .name = "syscalls:sys_enter_open:k", + .check = test__checkevent_tracepoint_modifier, + }, + [13] = { + .name = "syscalls:*:u", + .check = test__checkevent_tracepoint_multi_modifier, + }, + [14] = { + .name = "r1a:kp", + .check = test__checkevent_raw_modifier, + }, + [15] = { + .name = "1:1:hp", + .check = test__checkevent_numeric_modifier, + }, + [16] = { + .name = "instructions:h", + .check = test__checkevent_symbolic_name_modifier, + }, + [17] = { + .name = "faults:u", + .check = test__checkevent_symbolic_alias_modifier, + }, + [18] = { + .name = "L1-dcache-load-miss:kp", + .check = test__checkevent_genhw_modifier, + }, + [19] = { + .name = "mem:0:u", + .check = test__checkevent_breakpoint_modifier, + }, + [20] = { + .name = "mem:0:x:k", + .check = test__checkevent_breakpoint_x_modifier, + }, + [21] = { + .name = "mem:0:r:hp", + .check = test__checkevent_breakpoint_r_modifier, + }, + [22] = { + .name = "mem:0:w:up", + .check = test__checkevent_breakpoint_w_modifier, + }, + [23] = { + .name = "r1,syscalls:sys_enter_open:k,1:1:hp", + .check = test__checkevent_list, + }, + [24] = { + .name = "instructions:G", + .check = test__checkevent_exclude_host_modifier, + }, + [25] = { + .name = "instructions:H", + .check = test__checkevent_exclude_guest_modifier, + }, +}; + +#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) + +static struct test__event_st test__events_pmu[] = { + [0] = { + .name = "cpu/config=10,config1,config2=3,period=1000/u", + .check = test__checkevent_pmu, + }, +}; + +#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ + sizeof(struct test__event_st)) + +static int test(struct test__event_st *e) +{ + struct perf_evlist *evlist; + int ret; + + evlist = perf_evlist__new(NULL, NULL); + if (evlist == NULL) + return -ENOMEM; + + ret = parse_events(evlist, e->name, 0); + if (ret) { + pr_debug("failed to parse event '%s', err %d\n", + e->name, ret); + return ret; + } + + ret = e->check(evlist); + perf_evlist__delete(evlist); + + return ret; +} + +static int test_events(struct test__event_st *events, unsigned cnt) +{ + int ret = 0; + unsigned i; + + for (i = 0; i < cnt; i++) { + struct test__event_st *e = &events[i]; + + pr_debug("running test %d '%s'\n", i, e->name); + ret = test(e); + if (ret) + break; + } + + return ret; +} + +static int test_pmu(void) +{ + struct stat st; + char path[PATH_MAX]; + int ret; + + snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/", + sysfs_find_mountpoint()); + + ret = stat(path, &st); + if (ret) + pr_debug("ommiting PMU cpu tests\n"); + return !ret; +} + +int parse_events__test(void) +{ + int ret; + + ret = test_events(test__events, TEST__EVENTS_CNT); + if (!ret && test_pmu()) + ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT); + + return ret; +} diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 3fddd610d350..d287adc2bb61 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -4,7 +4,9 @@ * Parse symbolic events/counts passed in as options: */ +#include #include +#include "types.h" #include "../../../include/linux/perf_event.h" #include "types.h" @@ -86,6 +88,7 @@ void parse_events_update_lists(struct list_head *list_event, void parse_events_error(struct list_head *list_all, struct list_head *list_event, int *idx, char const *msg); +int parse_events__test(void); void print_events(const char *event_glob); void print_events_type(u8 type); -- cgit v1.2.3 From 82ba1f2f614871b388cb1bd58594507b6f0f2b79 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 21 May 2012 09:12:50 +0200 Subject: perf tools: Add support for displaying event parser debug info Adding PARSER_DEBUG Makefile variable to enable building event scanner/ parser with debug enabled. This results in verbose output right out of the scanner/parser. It's useful for debuging the event parser. Keeping this only for event parser so far. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337584373-2741-3-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 12 +++++++++--- tools/perf/util/parse-events.c | 6 ++++++ 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 91840e171815..b24623645ef6 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -83,7 +83,13 @@ ifndef PERF_DEBUG CFLAGS_OPTIMIZE = -O6 endif -CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) +ifdef PARSER_DEBUG + PARSER_DEBUG_BISON := -t + PARSER_DEBUG_FLEX := -d + PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG +endif + +CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS) EXTLIBS = -lpthread -lrt -lelf -lm ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE ALL_LDFLAGS = $(LDFLAGS) @@ -216,10 +222,10 @@ FLEX = flex BISON= bison $(OUTPUT)util/parse-events-flex.c: util/parse-events.l - $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c + $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c: util/parse-events.y - $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c + $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c $(OUTPUT)util/pmu-flex.c: util/pmu.l $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c7fc18a33d54..6704978736cc 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -23,6 +23,9 @@ struct event_symbol { const char *alias; }; +#ifdef PARSER_DEBUG +extern int parse_events_debug; +#endif int parse_events_parse(struct list_head *list, struct list_head *list_tmp, int *idx); @@ -768,6 +771,9 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) buffer = parse_events__scan_string(str); +#ifdef PARSER_DEBUG + parse_events_debug = 1; +#endif ret = parse_events_parse(&list, &list_tmp, &idx); parse_events__flush_buffer(buffer); -- cgit v1.2.3 From b847cbdc6750bdea248ace75c1868f8ef57dcdf0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 21 May 2012 09:12:51 +0200 Subject: perf tools: Use allocated list for each parsed event Switch from using static temporary event list into dynamically allocated one. This way we dont need to pass temp list to the parse_events_parse which makes the interface more clear. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337584373-2741-4-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 39 +++++++++++++++--------- tools/perf/util/parse-events.h | 16 ++++------ tools/perf/util/parse-events.y | 69 ++++++++++++++++++++++++++++++++---------- 3 files changed, 83 insertions(+), 41 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6704978736cc..4025e18765c4 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -26,8 +26,7 @@ struct event_symbol { #ifdef PARSER_DEBUG extern int parse_events_debug; #endif -int parse_events_parse(struct list_head *list, struct list_head *list_tmp, - int *idx); +int parse_events_parse(struct list_head *list, int *idx); #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x @@ -358,20 +357,30 @@ const char *__event_name(int type, u64 config) return "unknown"; } -static int add_event(struct list_head *list, int *idx, +static int add_event(struct list_head **_list, int *idx, struct perf_event_attr *attr, char *name) { struct perf_evsel *evsel; + struct list_head *list = *_list; + + if (!list) { + list = malloc(sizeof(*list)); + if (!list) + return -ENOMEM; + INIT_LIST_HEAD(list); + } event_attr_init(attr); evsel = perf_evsel__new(attr, (*idx)++); - if (!evsel) + if (!evsel) { + free(list); return -ENOMEM; - - list_add_tail(&evsel->node, list); + } evsel->name = strdup(name); + list_add_tail(&evsel->node, list); + *_list = list; return 0; } @@ -393,7 +402,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size) return -1; } -int parse_events_add_cache(struct list_head *list, int *idx, +int parse_events_add_cache(struct list_head **list, int *idx, char *type, char *op_result1, char *op_result2) { struct perf_event_attr attr; @@ -454,7 +463,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, return add_event(list, idx, &attr, name); } -static int add_tracepoint(struct list_head *list, int *idx, +static int add_tracepoint(struct list_head **list, int *idx, char *sys_name, char *evt_name) { struct perf_event_attr attr; @@ -491,7 +500,7 @@ static int add_tracepoint(struct list_head *list, int *idx, return add_event(list, idx, &attr, name); } -static int add_tracepoint_multi(struct list_head *list, int *idx, +static int add_tracepoint_multi(struct list_head **list, int *idx, char *sys_name, char *evt_name) { char evt_path[MAXPATHLEN]; @@ -522,7 +531,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx, return ret; } -int parse_events_add_tracepoint(struct list_head *list, int *idx, +int parse_events_add_tracepoint(struct list_head **list, int *idx, char *sys, char *event) { int ret; @@ -566,7 +575,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr) return 0; } -int parse_events_add_breakpoint(struct list_head *list, int *idx, +int parse_events_add_breakpoint(struct list_head **list, int *idx, void *ptr, char *type) { struct perf_event_attr attr; @@ -645,7 +654,7 @@ static int config_attr(struct perf_event_attr *attr, return 0; } -int parse_events_add_numeric(struct list_head *list, int *idx, +int parse_events_add_numeric(struct list_head **list, int *idx, unsigned long type, unsigned long config, struct list_head *head_config) { @@ -663,7 +672,7 @@ int parse_events_add_numeric(struct list_head *list, int *idx, (char *) __event_name(type, config)); } -int parse_events_add_pmu(struct list_head *list, int *idx, +int parse_events_add_pmu(struct list_head **list, int *idx, char *name, struct list_head *head_config) { struct perf_event_attr attr; @@ -696,7 +705,7 @@ void parse_events_update_lists(struct list_head *list_event, * list, for next event definition. */ list_splice_tail(list_event, list_all); - INIT_LIST_HEAD(list_event); + free(list_event); } int parse_events_modifier(struct list_head *list, char *str) @@ -774,7 +783,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) #ifdef PARSER_DEBUG parse_events_debug = 1; #endif - ret = parse_events_parse(&list, &list_tmp, &idx); + ret = parse_events_parse(&list, &idx); parse_events__flush_buffer(buffer); parse_events__delete_buffer(buffer); diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index d287adc2bb61..25ae3732f5b0 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -68,25 +68,21 @@ int parse_events__term_num(struct parse_events__term **_term, int parse_events__term_str(struct parse_events__term **_term, int type_term, char *config, char *str); void parse_events__free_terms(struct list_head *terms); -int parse_events_modifier(struct list_head *list __used, char *str __used); -int parse_events_add_tracepoint(struct list_head *list, int *idx, +int parse_events_modifier(struct list_head *list, char *str); +int parse_events_add_tracepoint(struct list_head **list, int *idx, char *sys, char *event); -int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config, - unsigned long config1, unsigned long config2, - char *mod); -int parse_events_add_numeric(struct list_head *list, int *idx, +int parse_events_add_numeric(struct list_head **list, int *idx, unsigned long type, unsigned long config, struct list_head *head_config); -int parse_events_add_cache(struct list_head *list, int *idx, +int parse_events_add_cache(struct list_head **list, int *idx, char *type, char *op_result1, char *op_result2); -int parse_events_add_breakpoint(struct list_head *list, int *idx, +int parse_events_add_breakpoint(struct list_head **list, int *idx, void *ptr, char *type); -int parse_events_add_pmu(struct list_head *list, int *idx, +int parse_events_add_pmu(struct list_head **list, int *idx, char *pmu , struct list_head *head_config); void parse_events_update_lists(struct list_head *list_event, struct list_head *list_all); void parse_events_error(struct list_head *list_all, - struct list_head *list_event, int *idx, char const *msg); int parse_events__test(void); diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 936913ea0ab6..126fad0a9936 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -1,7 +1,6 @@ %name-prefix "parse_events_" %parse-param {struct list_head *list_all} -%parse-param {struct list_head *list_event} %parse-param {int *idx} %{ @@ -41,6 +40,14 @@ do { \ %type PE_MODIFIER_BP %type event_config %type event_term +%type event_pmu +%type event_legacy_symbol +%type event_legacy_cache +%type event_legacy_mem +%type event_legacy_tracepoint +%type event_legacy_numeric +%type event_legacy_raw +%type event_def %union { @@ -62,13 +69,13 @@ event_def PE_MODIFIER_EVENT * (there could be more events added for multiple tracepoint * definitions via '*?'. */ - ABORT_ON(parse_events_modifier(list_event, $2)); - parse_events_update_lists(list_event, list_all); + ABORT_ON(parse_events_modifier($1, $2)); + parse_events_update_lists($1, list_all); } | event_def { - parse_events_update_lists(list_event, list_all); + parse_events_update_lists($1, list_all); } event_def: event_pmu | @@ -82,71 +89,102 @@ event_def: event_pmu | event_pmu: PE_NAME '/' event_config '/' { - ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3)); parse_events__free_terms($3); + $$ = list; } event_legacy_symbol: PE_VALUE_SYM '/' event_config '/' { + struct list_head *list = NULL; int type = $1 >> 16; int config = $1 & 255; - ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3)); + ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3)); parse_events__free_terms($3); + $$ = list; } | PE_VALUE_SYM sep_slash_dc { + struct list_head *list = NULL; int type = $1 >> 16; int config = $1 & 255; - ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL)); + ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL)); + $$ = list; } event_legacy_cache: PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT { - ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5)); + $$ = list; } | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT { - ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL)); + $$ = list; } | PE_NAME_CACHE_TYPE { - ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL)); + $$ = list; } event_legacy_mem: PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc { - ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4)); + $$ = list; } | PE_PREFIX_MEM PE_VALUE sep_dc { - ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL)); + $$ = list; } event_legacy_tracepoint: PE_NAME ':' PE_NAME { - ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3)); + $$ = list; } event_legacy_numeric: PE_VALUE ':' PE_VALUE { - ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL)); + $$ = list; } event_legacy_raw: PE_RAW { - ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL)); + struct list_head *list = NULL; + + ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL)); + $$ = list; } event_config: @@ -222,7 +260,6 @@ sep_slash_dc: '/' | ':' | %% void parse_events_error(struct list_head *list_all __used, - struct list_head *list_event __used, int *idx __used, char const *msg __used) { -- cgit v1.2.3 From 08d2f762ac4af861b962e543fceab341f05c8886 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 21 May 2012 09:12:52 +0200 Subject: perf tools: Separate 'mem:' event scanner bits Separating 'mem:' scanner processing, so we can parse out modifier specifically and dont clash with other rules. This is just precaution for the future, so we dont need to worry about the rules clashing where we need to parse out any sub-rule of global rules. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337584373-2741-5-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 1 + tools/perf/util/parse-events.l | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4025e18765c4..59324e7b3d8e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -787,6 +787,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used) parse_events__flush_buffer(buffer); parse_events__delete_buffer(buffer); + parse_events_lex_destroy(); if (!ret) { int entries = idx - evlist->nr_entries; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 1fcf1bbc5458..331d28a08dcb 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -1,5 +1,6 @@ %option prefix="parse_events_" +%option stack %{ #include @@ -50,6 +51,8 @@ static int term(int type) %} +%x mem + num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+ @@ -105,13 +108,12 @@ config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } -mem: { return PE_PREFIX_MEM; } +mem: { BEGIN(mem); return PE_PREFIX_MEM; } r{num_raw_hex} { return raw(); } {num_dec} { return value(10); } {num_hex} { return value(16); } {modifier_event} { return str(PE_MODIFIER_EVENT); } -{modifier_bp} { return str(PE_MODIFIER_BP); } {name} { return str(PE_NAME); } "/" { return '/'; } - { return '-'; } @@ -119,6 +121,25 @@ r{num_raw_hex} { return raw(); } : { return ':'; } = { return '='; } +{ +{modifier_bp} { return str(PE_MODIFIER_BP); } +: { return ':'; } +{num_dec} { return value(10); } +{num_hex} { return value(16); } + /* + * We need to separate 'mem:' scanner part, in order to get specific + * modifier bits parsed out. Otherwise we would need to handle PE_NAME + * and we'd need to parse it manually. During the escape from + * state we need to put the escaping char back, so we dont miss it. + */ +. { unput(*parse_events_text); BEGIN(INITIAL); } + /* + * We destroy the scanner after reaching EOF, + * but anyway just to be sure get back to INIT state. + */ +<> { BEGIN(INITIAL); } +} + %% int parse_events_wrap(void) -- cgit v1.2.3 From 6b5fc39bdd781711d7da8b95ae0243df3b35c5bf Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 21 May 2012 09:12:53 +0200 Subject: perf tools: Add hardcoded name term for pmu events Adding a new hardcoded term 'name' allowing to specify a name for the pmu event. The term is defined along with standard pmu terms. If no 'name' term is given, the event name follows following template: "raw 0x" running: perf stat -e cpu/config=1,name=krava1/u ls will produce following output: ... Performance counter stats for 'ls': 0 krava1 ... running: perf stat -e cpu/config=1/u ls will produce following output: ... Performance counter stats for 'ls': 0 raw 0x1 ... Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337584373-2741-6-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events-test.c | 25 +++++++++++++++++++++++++ tools/perf/util/parse-events.c | 23 ++++++++++++++++++++++- tools/perf/util/parse-events.h | 1 + tools/perf/util/parse-events.l | 1 + tools/perf/util/parse-events.y | 8 ++++++++ tools/perf/util/pmu.c | 4 ++-- 6 files changed, 59 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index 2e8f435384a6..76b98e2a587d 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c @@ -409,6 +409,27 @@ static int test__checkevent_list(struct perf_evlist *evlist) return 0; } +static int test__checkevent_pmu_name(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + /* cpu/config=1,name=krava1/u */ + evsel = list_entry(evlist->entries.next, struct perf_evsel, node); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); + TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava")); + + /* cpu/config=2/" */ + evsel = list_entry(evsel->node.next, struct perf_evsel, node); + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); + TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2")); + + return 0; +} + struct test__event_st { const char *name; __u32 type; @@ -529,6 +550,10 @@ static struct test__event_st test__events_pmu[] = { .name = "cpu/config=10,config1,config2=3,period=1000/u", .check = test__checkevent_pmu, }, + [1] = { + .name = "cpu/config=1,name=krava/u,cpu/config=2/u", + .check = test__checkevent_pmu_name, + }, }; #define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \ diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 59324e7b3d8e..fac7d59309b8 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -634,6 +634,9 @@ do { \ * attr->branch_sample_type = term->val.num; */ break; + case PARSE_EVENTS__TERM_TYPE_NAME: + CHECK_TYPE_VAL(STR); + break; default: return -EINVAL; } @@ -672,6 +675,23 @@ int parse_events_add_numeric(struct list_head **list, int *idx, (char *) __event_name(type, config)); } +static int parse_events__is_name_term(struct parse_events__term *term) +{ + return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME; +} + +static char *pmu_event_name(struct perf_event_attr *attr, + struct list_head *head_terms) +{ + struct parse_events__term *term; + + list_for_each_entry(term, head_terms, list) + if (parse_events__is_name_term(term)) + return term->val.str; + + return (char *) __event_name(PERF_TYPE_RAW, attr->config); +} + int parse_events_add_pmu(struct list_head **list, int *idx, char *name, struct list_head *head_config) { @@ -693,7 +713,8 @@ int parse_events_add_pmu(struct list_head **list, int *idx, if (perf_pmu__config(pmu, &attr, head_config)) return -EINVAL; - return add_event(list, idx, &attr, (char *) "pmu"); + return add_event(list, idx, &attr, + pmu_event_name(&attr, head_config)); } void parse_events_update_lists(struct list_head *list_event, diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 25ae3732f5b0..8cac57ab4ee6 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -47,6 +47,7 @@ enum { PARSE_EVENTS__TERM_TYPE_CONFIG, PARSE_EVENTS__TERM_TYPE_CONFIG1, PARSE_EVENTS__TERM_TYPE_CONFIG2, + PARSE_EVENTS__TERM_TYPE_NAME, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 331d28a08dcb..618a8e788399 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -105,6 +105,7 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); } config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } +name { return term(PARSE_EVENTS__TERM_TYPE_NAME); } period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 126fad0a9936..362cc59332ae 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -237,6 +237,14 @@ PE_NAME $$ = term; } | +PE_TERM '=' PE_NAME +{ + struct parse_events__term *term; + + ABORT_ON(parse_events__term_str(&term, $1, NULL, $3)); + $$ = term; +} +| PE_TERM '=' PE_VALUE { struct parse_events__term *term; diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 8ee219b7285b..a119a5371699 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -258,9 +258,9 @@ static int pmu_config_term(struct list_head *formats, static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, struct list_head *head_terms) { - struct parse_events__term *term, *h; + struct parse_events__term *term; - list_for_each_entry_safe(term, h, head_terms, list) + list_for_each_entry(term, head_terms, list) if (pmu_config_term(formats, attr, term)) return -EINVAL; -- cgit v1.2.3 From e326e7524531c5c6de4a8cf8eeed60b4a9f47637 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 22 May 2012 16:30:48 +0200 Subject: perf script: Explicitly handle known default print arg type Handle the print argument types brought by the new libparsevent in perl scripting engine. PRINT_BSTRING and PRINT_DYNAMIC_ARRAY are treated just like strings and thus don't require specific processing. But PRINT_FUNC need specific plugins which are not yet handled, lets warn if we meet this case. This fixes: util/scripting-engines/trace-event-perl.c: In function define_event_symbol: util/scripting-engines/trace-event-perl.c:188: error: enumeration value PRINT_BSTRING not handled in switch util/scripting-engines/trace-event-perl.c:188: error: enumeration value PRINT_DYNAMIC_ARRAY not handled in switch util/scripting-engines/trace-event-perl.c:188: error: enumeration value PRINT_FUNC not handled in switch Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Tom Zanussi Link: http://lkml.kernel.org/r/1337697049-30251-1-git-send-email-fweisbec@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/scripting-engines/trace-event-perl.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index e30749e38a9b..d50658b7d9e0 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -209,6 +209,8 @@ static void define_event_symbols(struct event *event, define_symbolic_values(args->symbol.symbols, ev_name, cur_field_name); break; + case PRINT_BSTRING: + case PRINT_DYNAMIC_ARRAY: case PRINT_STRING: break; case PRINT_TYPE: @@ -220,7 +222,9 @@ static void define_event_symbols(struct event *event, define_event_symbols(event, ev_name, args->op.left); define_event_symbols(event, ev_name, args->op.right); break; + case PRINT_FUNC: default: + pr_err("Unsupported print arg type\n"); /* we should warn... */ return; } -- cgit v1.2.3 From 8784eb7497b928de33a715e26da2bd51d424bec1 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Tue, 22 May 2012 16:30:49 +0200 Subject: perf script: Rename struct event to struct event_format in perl engine While migrating to the libtraceevent, the perl scripting engine missed this structure rename. This fixes: util/scripting-engines/trace-event-perl.c: In function "find_cache_event": util/scripting-engines/trace-event-perl.c:244: error: assignment from incompatible pointer type util/scripting-engines/trace-event-perl.c:248: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:248: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:250: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c: In function "perl_process_tracepoint": util/scripting-engines/trace-event-perl.c:286: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:286: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:307: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c: In function "perl_generate_script": util/scripting-engines/trace-event-perl.c:498: error: passing argument 1 of "trace_find_next_event" from incompatible pointer type util/scripting-engines/../trace-event.h:56: note: expected "struct event_format *" but argument is of type "struct event *" util/scripting-engines/trace-event-perl.c:498: error: assignment from incompatible pointer type util/scripting-engines/trace-event-perl.c:499: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:499: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:513: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:532: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:556: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:569: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:570: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:579: error: dereferencing pointer to incomplete type util/scripting-engines/trace-event-perl.c:580: error: dereferencing pointer to incomplete type Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Tom Zanussi Link: http://lkml.kernel.org/r/1337697049-30251-2-git-send-email-fweisbec@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/scripting-engines/trace-event-perl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index d50658b7d9e0..4c1b3d72a1d2 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -56,7 +56,7 @@ INTERP my_perl; #define FTRACE_MAX_EVENT \ ((1 << (sizeof(unsigned short) * 8)) - 1) -struct event *events[FTRACE_MAX_EVENT]; +struct event_format *events[FTRACE_MAX_EVENT]; extern struct scripting_context *scripting_context; @@ -181,7 +181,7 @@ static void define_flag_field(const char *ev_name, LEAVE; } -static void define_event_symbols(struct event *event, +static void define_event_symbols(struct event_format *event, const char *ev_name, struct print_arg *args) { @@ -233,10 +233,10 @@ static void define_event_symbols(struct event *event, define_event_symbols(event, ev_name, args->next); } -static inline struct event *find_cache_event(int type) +static inline struct event_format *find_cache_event(int type) { static char ev_name[256]; - struct event *event; + struct event_format *event; if (events[type]) return events[type]; @@ -262,7 +262,7 @@ static void perl_process_tracepoint(union perf_event *pevent __unused, static char handler[256]; unsigned long long val; unsigned long s, ns; - struct event *event; + struct event_format *event; int type; int pid; int cpu = sample->cpu; @@ -450,7 +450,7 @@ static int perl_stop_script(void) static int perl_generate_script(const char *outfile) { - struct event *event = NULL; + struct event_format *event = NULL; struct format_field *f; char fname[PATH_MAX]; int not_first, count; -- cgit v1.2.3 From 59f3bea53bfe2f395d548906fa39d01df620f0ac Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 May 2012 18:03:53 +0900 Subject: perf tools: Rename libparsevent to libtraceevent in Makefile Change some variable names according to new library name. Signed-off-by: Namhyung Kim Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1337677434-4881-1-git-send-email-namhyung.kim@lge.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index b24623645ef6..ef75a5570d94 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -155,7 +155,7 @@ endif ### --- END CONFIGURATION SECTION --- -BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(EVENT_PARSE_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE +BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE BASIC_LDFLAGS = # Guard against environment variables @@ -184,16 +184,16 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) -EVENT_PARSE_DIR = ../lib/traceevent/ +TRACE_EVENT_DIR = ../lib/traceevent/ ifeq ("$(origin O)", "command line") - EP_PATH=$(OUTPUT)/ + TE_PATH=$(OUTPUT)/ else - EP_PATH=$(EVENT_PARSE_DIR)/ + TE_PATH=$(TRACE_EVENT_DIR)/ endif -LIBPARSEVENT = $(EP_PATH)libtraceevent.a -EP_LIB := -L$(EP_PATH) -ltraceevent +LIBTRACEEVENT = $(TE_PATH)libtraceevent.a +TE_LIB := -L$(TE_PATH) -ltraceevent # # Single 'perf' binary right now: @@ -317,7 +317,7 @@ LIB_H += util/cpumap.h LIB_H += util/top.h LIB_H += $(ARCH_INCLUDE) LIB_H += util/cgroup.h -LIB_H += $(EVENT_PARSE_DIR)event-parse.h +LIB_H += $(TRACE_EVENT_DIR)event-parse.h LIB_H += util/target.h LIB_OBJS += $(OUTPUT)util/abspath.o @@ -417,7 +417,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o BUILTIN_OBJS += $(OUTPUT)builtin-test.o BUILTIN_OBJS += $(OUTPUT)builtin-inject.o -PERFLIBS = $(LIB_FILE) $(LIBPARSEVENT) +PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) # Files needed for the python binding, perf.so # pyrf is just an internal name needed for all those wrappers. @@ -826,9 +826,9 @@ $(sort $(dir $(DIRECTORY_DEPS))): $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) -# libparsevent.a -$(LIBPARSEVENT): - make -C $(EVENT_PARSE_DIR) $(COMMAND_O) libtraceevent.a +# libtraceevent.a +$(LIBTRACEEVENT): + $(MAKE) -C $(TRACE_EVENT_DIR) $(COMMAND_O) libtraceevent.a help: @echo 'Perf make targets:' -- cgit v1.2.3 From e33387fc2748ac78fd577dee2c914fc3ea0ba0cd Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 May 2012 18:03:54 +0900 Subject: perf tools: Always try to build libtraceevent Although perf depends on the libtraceevent, it cannot know when it needs to be rebuilt. So just try to rebuild it always in order to make sure we use the latest version. While at it, silence annoying directory change messages. Signed-off-by: Namhyung Kim Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1337677434-4881-2-git-send-email-namhyung.kim@lge.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ef75a5570d94..1d3d513beb9b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -828,7 +828,7 @@ $(LIB_FILE): $(LIB_OBJS) # libtraceevent.a $(LIBTRACEEVENT): - $(MAKE) -C $(TRACE_EVENT_DIR) $(COMMAND_O) libtraceevent.a + $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a help: @echo 'Perf make targets:' @@ -976,6 +976,6 @@ clean: $(RM) $(OUTPUT)util/*-{bison,flex}* $(python-clean) -.PHONY: all install clean strip +.PHONY: all install clean strip $(LIBTRACEEVENT) .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS -- cgit v1.2.3 From e40ee742d4542b4c046ac5426654b1494d87ad73 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Mon, 21 May 2012 10:42:07 +0900 Subject: perf target: Add cpu flag to sample_type if target has cpu Add PERF_SAMPLE_CPU flag into attr->sample_type if an user specified any of cpu target (either system-wide or cpu list). It will show correct values when cpu sort key is given for perf top and perf report. Signed-off-by: Namhyung Kim Cc: Ingo Molnar Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337564527-9367-1-git-send-email-namhyung.kim@lge.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 3 +++ tools/perf/util/evsel.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3e981a710c4d..18bd226f9f2b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -900,6 +900,9 @@ static void perf_top__start_counters(struct perf_top *top) attr->read_format |= PERF_FORMAT_ID; } + if (perf_target__has_cpu(&top->target)) + attr->sample_type |= PERF_SAMPLE_CPU; + if (symbol_conf.use_callchain) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f4f427ce4d64..9abd8ac508e2 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -108,7 +108,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, if (opts->call_graph) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; - if (opts->target.system_wide) + if (perf_target__has_cpu(&opts->target)) attr->sample_type |= PERF_SAMPLE_CPU; if (opts->period) -- cgit v1.2.3 From 2e49a948be1e282d2c1477c5a3b5ed23f5987723 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Fri, 18 May 2012 14:16:50 +0530 Subject: perf record: Fix documentation for branch stack sampling Signed-off-by: Anshuman Khandual Acked-by: Stephane Eranian Cc: Stephane Eranian Link: http://lkml.kernel.org/r/4FB60C7A.2080508@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index a1386b2fff00..b38a1f9ad460 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -168,7 +168,7 @@ following filters are defined: - any: any type of branches - any_call: any function call or system call - any_ret: any function return or system call return - - any_ind: any indirect branch + - ind_call: any indirect branch - u: only when the branch target is at the user level - k: only when the branch target is in the kernel - hv: only when the target is at the hypervisor level -- cgit v1.2.3 From e108c66e2c458f89931189a63a67ad16880d7f51 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 16 May 2012 08:59:03 +0200 Subject: perf tools: Carry perf_event_attr bitfield throught different endians When the perf data file is read cross architectures, the perf_event__attr_swap function takes care about endianness of all the struct fields except the bitfield flags. The bitfield flags need to be transformed as well, since the bitfield binary storage differs for both endians. ABI says: Bit-fields are allocated from right to left (least to most significant) on little-endian implementations and from left to right (most to least significant) on big-endian implementations. The above seems to be byte specific, so we need to reverse each byte of the bitfield. 'Internet' also says this might be implementation specific and we probably need proper fix and carry perf_event_attr bitfield flags in separate data file FEAT_ section. Thought this seems to work for now. Note, running following to test perf endianity handling: test 1) - origin system: # perf record -a -- sleep 10 (any perf record will do) # perf report > report.origin # perf archive perf.data - copy the perf.data, report.origin and perf.data.tar.bz2 to a target system and run: # tar xjvf perf.data.tar.bz2 -C ~/.debug # perf report > report.target # diff -u report.origin report.target - the diff should produce no output (besides some white space stuff and possibly different date/TZ output) test 2) - origin system: # perf record -ag -fo /tmp/perf.data -- sleep 1 - mount origin system root to the target system on /mnt/origin - target system: # perf script --symfs /mnt/origin -I -i /mnt/origin/tmp/perf.data \ --kallsyms /mnt/origin/proc/kallsyms - complete perf.data header is displayed Signed-off-by: Jiri Olsa Reviewed-by: David Ahern Tested-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337151548-2396-3-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4dcc8f3190cf..17c9ace445c4 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -481,6 +481,38 @@ static void perf_event__read_swap(union perf_event *event) event->read.id = bswap_64(event->read.id); } +static u8 revbyte(u8 b) +{ + int rev = (b >> 4) | ((b & 0xf) << 4); + rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2); + rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1); + return (u8) rev; +} + +/* + * XXX this is hack in attempt to carry flags bitfield + * throught endian village. ABI says: + * + * Bit-fields are allocated from right to left (least to most significant) + * on little-endian implementations and from left to right (most to least + * significant) on big-endian implementations. + * + * The above seems to be byte specific, so we need to reverse each + * byte of the bitfield. 'Internet' also says this might be implementation + * specific and we probably need proper fix and carry perf_event_attr + * bitfield flags in separate data file FEAT_ section. Thought this seems + * to work for now. + */ +static void swap_bitfield(u8 *p, unsigned len) +{ + unsigned i; + + for (i = 0; i < len; i++) { + *p = revbyte(*p); + p++; + } +} + /* exported for swapping attributes in file header */ void perf_event__attr_swap(struct perf_event_attr *attr) { @@ -494,6 +526,8 @@ void perf_event__attr_swap(struct perf_event_attr *attr) attr->bp_type = bswap_32(attr->bp_type); attr->bp_addr = bswap_64(attr->bp_addr); attr->bp_len = bswap_64(attr->bp_len); + + swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); } static void perf_event__hdr_attr_swap(union perf_event *event) -- cgit v1.2.3 From 6a11f92ef449bfb87f93e7cc14cb2a717afc7aa3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 16 May 2012 08:59:04 +0200 Subject: perf tools: Add union u64_swap type for swapping u64 data The following union: union { u64 val64; u32 val32[2]; } u; is used on more than one place in perf code and will be used more in upcomming patches. Adding union u64_swap to have it defined globaly so we dont need to redefine it all the time. Signed-off-by: Jiri Olsa Reviewed-by: David Ahern Tested-by: David Ahern Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337151548-2396-4-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 10 ++-------- tools/perf/util/types.h | 5 +++++ 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9abd8ac508e2..57e4ce57bbcc 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -462,10 +462,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, * used for cross-endian analysis. See git commit 65014ab3 * for why this goofiness is needed. */ - union { - u64 val64; - u32 val32[2]; - } u; + union u64_swap u; memset(data, 0, sizeof(*data)); data->cpu = data->pid = data->tid = -1; @@ -608,10 +605,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, * used for cross-endian analysis. See git commit 65014ab3 * for why this goofiness is needed. */ - union { - u64 val64; - u32 val32[2]; - } u; + union u64_swap u; array = event->sample.array; diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h index 5f3689a3d085..c51fa6b70a28 100644 --- a/tools/perf/util/types.h +++ b/tools/perf/util/types.h @@ -16,4 +16,9 @@ typedef signed short s16; typedef unsigned char u8; typedef signed char s8; +union u64_swap { + u64 val64; + u32 val32[2]; +}; + #endif /* __PERF_TYPES_H */ -- cgit v1.2.3 From 2eeaaa095d155d47d47d5df07571105b8ae76ffd Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 15 May 2012 13:28:13 +0200 Subject: perf tools: rename HEADER_TRACE_INFO to HEADER_TRACING_DATA To match the PERF_RECORD_HEADER_TRACING_DATA record type. This is the same info as the one used for pipe mode whereas the other one is for regular file output. This will help in the later patch to add meta-data infos in pipe mode. Signed-off-by: Stephane Eranian Cc: David Ahern Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337081295-10303-4-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 ++-- tools/perf/util/header.c | 10 +++++----- tools/perf/util/header.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8a3dfac161e2..9c76add6a03a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -396,7 +396,7 @@ static void perf_record__mmap_read_all(struct perf_record *rec) perf_record__mmap_read(rec, &rec->evlist->mmap[i]); } - if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO)) + if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) write_output(rec, &finished_round_event, sizeof(finished_round_event)); } @@ -478,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) perf_header__clear_feat(&session->header, HEADER_BUILD_ID); if (!have_tracepoints(&evsel_list->entries)) - perf_header__clear_feat(&session->header, HEADER_TRACE_INFO); + perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); if (!rec->opts.branch_stack) perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 538598012139..2dd5edf161b7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -437,7 +437,7 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with return ret; } -static int write_trace_info(int fd, struct perf_header *h __used, +static int write_tracing_data(int fd, struct perf_header *h __used, struct perf_evlist *evlist) { return read_tracing_data(fd, &evlist->entries); @@ -1472,7 +1472,7 @@ out: return err; } -static int process_trace_info(struct perf_file_section *section __unused, +static int process_tracing_data(struct perf_file_section *section __unused, struct perf_header *ph __unused, int feat __unused, int fd) { @@ -1508,11 +1508,11 @@ struct feature_ops { .full_only = true } /* feature_ops not implemented: */ -#define print_trace_info NULL -#define print_build_id NULL +#define print_tracing_data NULL +#define print_build_id NULL static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { - FEAT_OPP(HEADER_TRACE_INFO, trace_info), + FEAT_OPP(HEADER_TRACING_DATA, tracing_data), FEAT_OPP(HEADER_BUILD_ID, build_id), FEAT_OPA(HEADER_HOSTNAME, hostname), FEAT_OPA(HEADER_OSRELEASE, osrelease), diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 21a6be09c129..2d42b3e1826f 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -12,7 +12,7 @@ enum { HEADER_RESERVED = 0, /* always cleared */ HEADER_FIRST_FEATURE = 1, - HEADER_TRACE_INFO = 1, + HEADER_TRACING_DATA = 1, HEADER_BUILD_ID, HEADER_HOSTNAME, -- cgit v1.2.3 From 1a1ed1ba6778a5bc5702cebe276ab080a0b78115 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 15 May 2012 13:28:11 +0200 Subject: perf inject: Fix broken perf inject -b perf inject -b was broken. It would not inject any build_id into the stream. Furthermore, it would strip samples from the stream. The reason was a missing initialization of the event attribute structure. The perf_tool.tool.attr() callback was pointing to a simple repipe. But there was no initialization of the internal data structures to keep track of events and event ids. That later caused event id lookups to fail, and sample would get removed. The patch simply adds back the call to perf_event__process_attr() to initialize the evlist structure and now build_ids are again injected. Signed-off-by: Stephane Eranian Cc: David Ahern Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337081295-10303-2-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 09c106193e65..3beab489afc5 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -60,6 +60,11 @@ static int perf_event__repipe_tracing_data_synth(union perf_event *event, static int perf_event__repipe_attr(union perf_event *event, struct perf_evlist **pevlist __used) { + int ret; + ret = perf_event__process_attr(event, pevlist); + if (ret) + return ret; + return perf_event__repipe_synth(NULL, event, NULL); } -- cgit v1.2.3 From 444d28663936e286c752f05feca44d6041b1fce4 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 15 May 2012 13:28:12 +0200 Subject: perf tools: Fix piped mode read code In __perf_session__process_pipe_events(), there was a risk we would read more than what a union perf_event struct can hold. this could happen in case, perf is reading a file which contains new record types it does not know about and which are larger than anything it knows about. In general, perf is supposed to skip records it does not understand, but in pipe mode, those have to be read and ignored. The fixed size header contains the size of the record, but that size may be larger than union perf_event, yet it was used as the backing to the read in: union perf_event event; void *p; size = event->header.size; p = &event; p += sizeof(struct perf_event_header); if (size - sizeof(struct perf_event_header)) { err = readn(self->fd, p, size - sizeof(struct perf_event_header)); We fix this by allocating a buffer based on the size reported in the header. We reuse the buffer as much as we can. We realloc in case it becomes too small. In the common case, the performance impact is negligible. Signed-off-by: Stephane Eranian Cc: David Ahern Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337081295-10303-3-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 17c9ace445c4..93d355d27109 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1098,8 +1098,9 @@ volatile int session_done; static int __perf_session__process_pipe_events(struct perf_session *self, struct perf_tool *tool) { - union perf_event event; - uint32_t size; + union perf_event *event; + uint32_t size, cur_size = 0; + void *buf = NULL; int skip = 0; u64 head; int err; @@ -1108,8 +1109,14 @@ static int __perf_session__process_pipe_events(struct perf_session *self, perf_tool__fill_defaults(tool); head = 0; + cur_size = sizeof(union perf_event); + + buf = malloc(cur_size); + if (!buf) + return -errno; more: - err = readn(self->fd, &event, sizeof(struct perf_event_header)); + event = buf; + err = readn(self->fd, event, sizeof(struct perf_event_header)); if (err <= 0) { if (err == 0) goto done; @@ -1119,13 +1126,23 @@ more: } if (self->header.needs_swap) - perf_event_header__bswap(&event.header); + perf_event_header__bswap(&event->header); - size = event.header.size; + size = event->header.size; if (size == 0) size = 8; - p = &event; + if (size > cur_size) { + void *new = realloc(buf, size); + if (!new) { + pr_err("failed to allocate memory to read event\n"); + goto out_err; + } + buf = new; + cur_size = size; + event = buf; + } + p = event; p += sizeof(struct perf_event_header); if (size - sizeof(struct perf_event_header)) { @@ -1141,9 +1158,9 @@ more: } } - if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { + if ((skip = perf_session__process_event(self, event, tool, head)) < 0) { pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", - head, event.header.size, event.header.type); + head, event->header.size, event->header.type); err = -EINVAL; goto out_err; } @@ -1158,6 +1175,7 @@ more: done: err = 0; out_err: + free(buf); perf_session__warn_about_errors(self, tool); perf_session_free_sample_buffers(self); return err; -- cgit v1.2.3 From 299c345208ae15fbc1e1c96dc1b6ac61e4e5da10 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 15 May 2012 13:28:15 +0200 Subject: perf buildid-list: Work better with pipe mode In order for perf buildid-list to work with pipe-mode files, it needs to process buildids and event attr structs. $ perf record -o - noploop 2 | ./perf inject -b | perf buildid-list -i - -H noploop for 2 seconds [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.084 MB - (~3678 samples) ] 0000000000000000000000000000000000000000 [kernel.kallsyms] 3a0d0629efe74a8da3eeba372cdbd74ad9b8f5d5 /usr/local/bin/noploop The reason [kernel.kallsyms] shows a 0 build-id comes from the way buildids are injected in the stream. The buildid for the kernel is provided by a BUILD_ID record. The [kernel.kallsyms] is provided by a MMAP record. There is no clean and obvious way to link the two, unfortunately. In regular mode, the kernel buildid is generated from reading the ELF image or kallsyms and perf knows to associate [kernel.kallsyms] to it. Later on, when perf processes the [kernel.kallsyms] MMAP record, it will already have a dso for it. So for now, make sure perf buildid-list shows the buildids for everything but the kernel image. Signed-off-by: Stephane Eranian Cc: David Ahern Cc: Ingo Molnar Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1337081295-10303-6-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-buildid-list.c | 6 +++++- tools/perf/util/build-id.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 52480467e9ff..6b2bcfbde150 100644 --- a/tools/perf/builtin-buildid-list.c +++ b/tools/perf/builtin-buildid-list.c @@ -84,7 +84,11 @@ static int perf_session__list_build_ids(void) if (filename__fprintf_build_id(session->filename, stdout)) goto out; - if (with_hits) + /* + * in pipe-mode, the only way to get the buildids is to parse + * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID + */ + if (with_hits || session->fd_pipe) perf_session__process_events(session, &build_id__mark_dso_hit_ops); perf_session__fprintf_dsos_buildid(session, stdout, with_hits); diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index dff9c7a725f4..fd9a5944b627 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -65,6 +65,8 @@ struct perf_tool build_id__mark_dso_hit_ops = { .mmap = perf_event__process_mmap, .fork = perf_event__process_task, .exit = perf_event__exit_del_thread, + .attr = perf_event__process_attr, + .build_id = perf_event__process_build_id, }; char *dso__build_id_filename(struct dso *self, char *bf, size_t size) -- cgit v1.2.3 From 447a6013e91738c0d4118a7d0c56f235d8623695 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 22 May 2012 13:14:18 -0300 Subject: perf tools: Bump default sample freq to 4 kHz Quoting Ingo: "While at it I'd also suggest increasing the default sampling frequency, from 1000 Hz per CPU to at least 4Khz auto-freq or so - this should work well all across the board I think. CPUs are getting faster and command/app run times are getting shorter, 1Khz is a bit low IMO." Requested-by: Ingo Molnar Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2jafa6mkrufyekny9ei59lpu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-top.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9c76add6a03a..e5cb08427e13 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -753,7 +753,7 @@ static struct perf_record record = { .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, - .freq = 1000, + .freq = 4000, .target = { .uses_mmap = true, }, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 18bd226f9f2b..6031dce0429f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1162,7 +1162,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) struct perf_top top = { .count_filter = 5, .delay_secs = 2, - .freq = 1000, /* 1 KHz */ + .freq = 4000, /* 4 KHz */ .mmap_pages = 128, .sym_pcnt_filter = 5, .target = { -- cgit v1.2.3 From 26252ea675663d1bc6747125fcaa2b7cc4ed8a03 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 22 May 2012 14:30:11 -0300 Subject: perf evlist: Show event attribute details There was no easy way to see the frequency used, and with the change of default, we better provide one. [root@sandy linux]# perf evlist -F cycles: sample_freq=4000 [root@sandy linux]# perf evlist -v cycles: sample_freq=4000, size: 80, sample_type: 391, read_format: 7, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, sample_id_all: 1, exclude_guest: 1 [root@sandy linux]# Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-e1p9poez3nwrgycbmwqmhlsu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-evlist.txt | 8 +++ tools/perf/builtin-evlist.c | 103 +++++++++++++++++++++++++++---- 2 files changed, 100 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt index 0507ec7bad71..15217345c2fa 100644 --- a/tools/perf/Documentation/perf-evlist.txt +++ b/tools/perf/Documentation/perf-evlist.txt @@ -20,6 +20,14 @@ OPTIONS --input=:: Input file name. (default: perf.data unless stdin is a fifo) +-F:: +--freq=:: + Show just the sample frequency used for each event. + +-v:: +--verbose=:: + Show all fields. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-list[1], diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 26760322c4f4..e52d77ec7084 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -15,9 +15,40 @@ #include "util/parse-options.h" #include "util/session.h" -static const char *input_name; +struct perf_attr_details { + bool freq; + bool verbose; +}; + +static int comma_printf(bool *first, const char *fmt, ...) +{ + va_list args; + int ret = 0; + + if (!*first) { + ret += printf(","); + } else { + ret += printf(":"); + *first = false; + } + + va_start(args, fmt); + ret += vprintf(fmt, args); + va_end(args); + return ret; +} + +static int __if_print(bool *first, const char *field, u64 value) +{ + if (value == 0) + return 0; + + return comma_printf(first, " %s: %" PRIu64, field, value); +} + +#define if_print(field) __if_print(&first, #field, pos->attr.field) -static int __cmd_evlist(void) +static int __cmd_evlist(const char *input_name, struct perf_attr_details *details) { struct perf_session *session; struct perf_evsel *pos; @@ -26,8 +57,52 @@ static int __cmd_evlist(void) if (session == NULL) return -ENOMEM; - list_for_each_entry(pos, &session->evlist->entries, node) - printf("%s\n", event_name(pos)); + list_for_each_entry(pos, &session->evlist->entries, node) { + bool first = true; + + printf("%s", event_name(pos)); + + if (details->verbose || details->freq) { + comma_printf(&first, " sample_freq=%" PRIu64, + (u64)pos->attr.sample_freq); + } + + if (details->verbose) { + if_print(type); + if_print(config); + if_print(config1); + if_print(config2); + if_print(size); + if_print(sample_type); + if_print(read_format); + if_print(disabled); + if_print(inherit); + if_print(pinned); + if_print(exclusive); + if_print(exclude_user); + if_print(exclude_kernel); + if_print(exclude_hv); + if_print(exclude_idle); + if_print(mmap); + if_print(comm); + if_print(freq); + if_print(inherit_stat); + if_print(enable_on_exec); + if_print(task); + if_print(watermark); + if_print(precise_ip); + if_print(mmap_data); + if_print(sample_id_all); + if_print(exclude_host); + if_print(exclude_guest); + if_print(__reserved_1); + if_print(wakeup_events); + if_print(bp_type); + if_print(branch_sample_type); + } + + putchar('\n'); + } perf_session__delete(session); return 0; @@ -38,17 +113,23 @@ static const char * const evlist_usage[] = { NULL }; -static const struct option options[] = { - OPT_STRING('i', "input", &input_name, "file", - "input file name"), - OPT_END() -}; - int cmd_evlist(int argc, const char **argv, const char *prefix __used) { + struct perf_attr_details details = { .verbose = false, }; + const char *input_name; + const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", + "Input file name"), + OPT_BOOLEAN('F', "freq", &details.freq, + "Show the sample frequency"), + OPT_BOOLEAN('v', "verbose", &details.verbose, + "Show all event attr details"), + OPT_END() + }; + argc = parse_options(argc, argv, options, evlist_usage, 0); if (argc) usage_with_options(evlist_usage, options); - return __cmd_evlist(); + return __cmd_evlist(input_name, &details); } -- cgit v1.2.3