From 5bcdf5e4fee3c45e1281c25e4941f2163cb28c65 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 18 May 2012 12:40:42 +0200 Subject: perf/x86: Update event scheduling constraints for AMD family 15h models This update is for newer family 15h cpu models from 0x02 to 0x1f. Signed-off-by: Robert Richter Acked-by: Peter Zijlstra Cc: Stephane Eranian Cc: stable@vger.kernel.org # v2.6.39+ Link: http://lkml.kernel.org/r/1337337642-1621-1-git-send-email-robert.richter@amd.com Signed-off-by: Ingo Molnar diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c index 95e7fe1..9edc786 100644 --- a/arch/x86/kernel/cpu/perf_event_amd.c +++ b/arch/x86/kernel/cpu/perf_event_amd.c @@ -493,6 +493,7 @@ static __initconst const struct x86_pmu amd_pmu = { * 0x023 DE PERF_CTL[2:0] * 0x02D LS PERF_CTL[3] * 0x02E LS PERF_CTL[3,0] + * 0x031 LS PERF_CTL[2:0] (**) * 0x043 CU PERF_CTL[2:0] * 0x045 CU PERF_CTL[2:0] * 0x046 CU PERF_CTL[2:0] @@ -506,10 +507,12 @@ static __initconst const struct x86_pmu amd_pmu = { * 0x0DD LS PERF_CTL[5:0] * 0x0DE LS PERF_CTL[5:0] * 0x0DF LS PERF_CTL[5:0] + * 0x1C0 EX PERF_CTL[5:3] * 0x1D6 EX PERF_CTL[5:0] * 0x1D8 EX PERF_CTL[5:0] * - * (*) depending on the umask all FPU counters may be used + * (*) depending on the umask all FPU counters may be used + * (**) only one unitmask enabled at a time */ static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0); @@ -559,6 +562,12 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev return &amd_f15_PMC3; case 0x02E: return &amd_f15_PMC30; + case 0x031: + if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1) + return &amd_f15_PMC20; + return &emptyconstraint; + case 0x1C0: + return &amd_f15_PMC53; default: return &amd_f15_PMC50; } -- cgit v0.10.2 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 diff --git a/tools/perf/Makefile b/tools/perf/Makefile index fa37cd5..91840e1 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 6c47376..5a8727c 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 0000000..2e8f435 --- /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 3fddd61..d287adc 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 v0.10.2 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 diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 91840e1..b246236 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 c7fc18a..6704978 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 v0.10.2 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 diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6704978..4025e18 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 d287adc..25ae373 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 936913e..126fad0 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 v0.10.2 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 diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4025e18..59324e7 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 1fcf1bb..331d28a 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 v0.10.2 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 diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c index 2e8f435..76b98e2 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 59324e7..fac7d59 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 25ae373..8cac57a 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 331d28a..618a8e7 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 126fad0..362cc59 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 8ee219b..a119a53 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 v0.10.2 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 diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index e30749e..d50658b 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 v0.10.2 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 diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index d50658b..4c1b3d7 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 v0.10.2 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 diff --git a/tools/perf/Makefile b/tools/perf/Makefile index b246236..ef75a55 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 v0.10.2 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 diff --git a/tools/perf/Makefile b/tools/perf/Makefile index ef75a55..1d3d513 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 v0.10.2 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 diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3e981a7..18bd226 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 f4f427c..9abd8ac 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 v0.10.2 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 diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index a1386b2..b38a1f9 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 v0.10.2 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 diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4dcc8f3..17c9ace 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 v0.10.2 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 diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9abd8ac..57e4ce5 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 5f3689a..c51fa6b 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 v0.10.2 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 diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8a3dfac..9c76add 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 5385980..2dd5edf 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 21a6be0..2d42b3e 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 v0.10.2 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 diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 09c1061..3beab48 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 v0.10.2 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 diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 17c9ace..93d355d 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 v0.10.2 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 diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c index 5248046..6b2bcfb 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 dff9c7a..fd9a594 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 v0.10.2 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 diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 9c76add..e5cb084 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 18bd226..6031dce 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 v0.10.2 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 diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt index 0507ec7..1521734 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 2676032..e52d77e 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 v0.10.2 From ab0cce560ef177bdc7a8f73e9962be9d829a7b2c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 May 2012 13:13:02 +0200 Subject: Revert "sched, perf: Use a single callback into the scheduler" This reverts commit cb04ff9ac424 ("sched, perf: Use a single callback into the scheduler"). Before this change was introduced, the process switch worked like this (wrt. to perf event schedule): schedule (prev, next) - schedule out all perf events for prev - switch to next - schedule in all perf events for current (next) After the commit, the process switch looks like: schedule (prev, next) - schedule out all perf events for prev - schedule in all perf events for (next) - switch to next The problem is, that after we schedule perf events in, the pmu is enabled and we can receive events even before we make the switch to next - so "current" still being prev process (event SAMPLE data are filled based on the value of the "current" process). Thats exactly what we see for test__PERF_RECORD test. We receive SAMPLES with PID of the process that our tracee is scheduled from. Discussed with Peter Zijlstra: > Bah!, yeah I guess reverting is the right thing for now. Sad > though. > > So by having the two hooks we have a black-spot between them > where we receive no events at all, this black-spot covers the > hand-over of current and we thus don't receive the 'wrong' > events. > > I rather liked we could do away with both that black-spot and > clean up the code a little, but apparently people rely on it. Signed-off-by: Jiri Olsa Acked-by: Peter Zijlstra Cc: acme@redhat.com Cc: paulus@samba.org Cc: cjashfor@linux.vnet.ibm.com Cc: fweisbec@gmail.com Cc: eranian@google.com Link: http://lkml.kernel.org/r/20120523111302.GC1638@m.brq.redhat.com Signed-off-by: Ingo Molnar diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 8adf70e..f325786 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1084,8 +1084,10 @@ extern void perf_pmu_unregister(struct pmu *pmu); extern int perf_num_counters(void); extern const char *perf_pmu_name(void); -extern void __perf_event_task_sched(struct task_struct *prev, - struct task_struct *next); +extern void __perf_event_task_sched_in(struct task_struct *prev, + struct task_struct *task); +extern void __perf_event_task_sched_out(struct task_struct *prev, + struct task_struct *next); extern int perf_event_init_task(struct task_struct *child); extern void perf_event_exit_task(struct task_struct *child); extern void perf_event_free_task(struct task_struct *task); @@ -1205,13 +1207,20 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) extern struct static_key_deferred perf_sched_events; -static inline void perf_event_task_sched(struct task_struct *prev, +static inline void perf_event_task_sched_in(struct task_struct *prev, struct task_struct *task) { + if (static_key_false(&perf_sched_events.key)) + __perf_event_task_sched_in(prev, task); +} + +static inline void perf_event_task_sched_out(struct task_struct *prev, + struct task_struct *next) +{ perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); if (static_key_false(&perf_sched_events.key)) - __perf_event_task_sched(prev, task); + __perf_event_task_sched_out(prev, next); } extern void perf_event_mmap(struct vm_area_struct *vma); @@ -1286,8 +1295,11 @@ extern void perf_event_disable(struct perf_event *event); extern void perf_event_task_tick(void); #else static inline void -perf_event_task_sched(struct task_struct *prev, - struct task_struct *task) { } +perf_event_task_sched_in(struct task_struct *prev, + struct task_struct *task) { } +static inline void +perf_event_task_sched_out(struct task_struct *prev, + struct task_struct *next) { } static inline int perf_event_init_task(struct task_struct *child) { return 0; } static inline void perf_event_exit_task(struct task_struct *child) { } static inline void perf_event_free_task(struct task_struct *task) { } diff --git a/kernel/events/core.c b/kernel/events/core.c index 91a4459..5b06cbb 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2039,8 +2039,8 @@ static void perf_event_context_sched_out(struct task_struct *task, int ctxn, * accessing the event control register. If a NMI hits, then it will * not restart the event. */ -static void __perf_event_task_sched_out(struct task_struct *task, - struct task_struct *next) +void __perf_event_task_sched_out(struct task_struct *task, + struct task_struct *next) { int ctxn; @@ -2279,8 +2279,8 @@ static void perf_branch_stack_sched_in(struct task_struct *prev, * accessing the event control register. If a NMI hits, then it will * keep the event running. */ -static void __perf_event_task_sched_in(struct task_struct *prev, - struct task_struct *task) +void __perf_event_task_sched_in(struct task_struct *prev, + struct task_struct *task) { struct perf_event_context *ctx; int ctxn; @@ -2305,12 +2305,6 @@ static void __perf_event_task_sched_in(struct task_struct *prev, perf_branch_stack_sched_in(prev, task); } -void __perf_event_task_sched(struct task_struct *prev, struct task_struct *next) -{ - __perf_event_task_sched_out(prev, next); - __perf_event_task_sched_in(prev, next); -} - static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) { u64 frequency = event->attr.sample_freq; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 13c3883..0533a68 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1913,7 +1913,7 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) { sched_info_switch(prev, next); - perf_event_task_sched(prev, next); + perf_event_task_sched_out(prev, next); fire_sched_out_preempt_notifiers(prev, next); prepare_lock_switch(rq, next); prepare_arch_switch(next); @@ -1956,6 +1956,13 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev) */ prev_state = prev->state; finish_arch_switch(prev); +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + local_irq_disable(); +#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ + perf_event_task_sched_in(prev, current); +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + local_irq_enable(); +#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ finish_lock_switch(rq, prev); finish_arch_post_lock_switch(); -- cgit v0.10.2