From 4498062e72fd55b2a9a4ac1b44fab8cb44ad5367 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Feb 2011 10:07:42 -0200 Subject: [PATCH 1/6] perf python: Add cgroup.c to setup.py to get it building again The 023695d cset added a new file, util/cgroup.c, that is referenced from util/evsel.c, so it needs to be present in util/setup.py so that the python shared object binding works, fixing this: [root@emilia linux]# export PYTHONPATH=~acme/git/build/perf/python/ [root@emilia linux]# ./tools/perf/python/twatch.py Traceback (most recent call last): File "./tools/perf/python/twatch.py", line 16, in import perf ImportError: /home/acme/git/build/perf/python/perf.so: undefined symbol: close_cgroup Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 1947b0430c94..e24ffadb20b2 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -5,7 +5,7 @@ from distutils.core import setup, Extension perf = Extension('perf', sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', - 'util/util.c', 'util/xyarray.c'], + 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], include_dirs = ['util/include'], extra_compile_args = ['-fno-strict-aliasing', '-Wno-write-strings']) From f0c55bcf4aa41b4b1dbee826513b1acb01bf65e1 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 16 Feb 2011 15:10:01 +0200 Subject: [PATCH 2/6] perf: make perf stat print user provided full event names This patch changes the way perf stat prints event names at the end of a run. Until now, it was trying to reconstruct the event name from its encoding. The problem is that it would only print generic events without their modifiers (u, k, pp). This patch saves the event name as passed by the user in the evsel struct and uses it to print the final event name. This would also work in case perf is linked with a library (such as libpfm4) which provides full PMU event tables. $ perf stat -e cycles:u,cycles:k date Wed Feb 16 14:58:52 CET 2011 Performance counter stats for 'date': 568600 cycles:u 2779715 cycles:k 0.001908182 seconds time elapsed Cc: Arun Sharma Cc: David S. Miller Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Robert Richter Cc: Stephane Eranian LPU-Reference: <4d5bdc64.98a1df0a.7aa3.06c2@mx.google.com> Signed-off-by: Stephane Eranian [ committer note: Fixed a merge problem with 023695d "Add cgroup support" ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 1 + tools/perf/util/evsel.h | 7 +++++++ tools/perf/util/parse-events.c | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c974e08d07ab..63cadaf3e208 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -86,6 +86,7 @@ void perf_evsel__delete(struct perf_evsel *evsel) { perf_evsel__exit(evsel); close_cgroup(evsel->cgrp); + free(evsel->name); free(evsel); } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 1d3d5a3dbe60..f6fc8f651a25 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -37,6 +37,12 @@ struct perf_sample_id { struct perf_evsel *evsel; }; +/** struct perf_evsel - event selector + * + * @name - Can be set to retain the original event name passed by the user, + * so that when showing results in tools such as 'perf stat', we + * show the name used, not some alias. + */ struct perf_evsel { struct list_head node; struct perf_event_attr attr; @@ -45,6 +51,7 @@ struct perf_evsel { struct xyarray *id; struct perf_counts *counts; int idx; + char *name; void *priv; struct cgroup_sel *cgrp; }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index cf082daa43e3..80a3dd5ef573 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -268,6 +268,9 @@ const char *event_name(struct perf_evsel *evsel) u64 config = evsel->attr.config; int type = evsel->attr.type; + if (evsel->name) + return evsel->name; + return __event_name(type, config); } @@ -782,8 +785,10 @@ int parse_events(const struct option *opt, const char *str, int unset __used) struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; struct perf_event_attr attr; enum event_result ret; + const char *ostr; for (;;) { + ostr = str; memset(&attr, 0, sizeof(attr)); ret = parse_event_symbols(opt, &str, &attr); if (ret == EVT_FAILED) @@ -798,6 +803,11 @@ int parse_events(const struct option *opt, const char *str, int unset __used) if (evsel == NULL) return -1; perf_evlist__add(evlist, evsel); + + evsel->name = calloc(str - ostr + 1, 1); + if (!evsel->name) + return -1; + strncpy(evsel->name, ostr, str - ostr); } if (*str == 0) From fec9cbd15b9e99bab9bc50f1ed7e20a1087d7c6d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Feb 2011 10:37:23 -0200 Subject: [PATCH 3/6] perf hists: Print number of samples, not the period sum So that we match the header where we state the number of events with the "Samples" column when using 'perf report -n/--show-nr-samples': [root@emilia ~]# perf record -a sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.111 MB perf.data (~4860 samples) ] [root@emilia ~]# perf report --stdio --show-nr-samples # Events: 11 cycles # # Overhead Samples Command Shared Object Symbol # ........ .......... ........... .................. ............................ # 16.65% 1 sleep [kernel.kallsyms] [k] unmap_vmas 16.10% 1 perf libpthread-2.12.so [.] __pthread_cleanup_push_defer 15.79% 2 perf [kernel.kallsyms] [k] format_decode 12.88% 1 kworker/1:2 [kernel.kallsyms] [k] cache_reap 10.69% 1 swapper [kernel.kallsyms] [k] _raw_spin_lock 7.55% 1 sleep [kernel.kallsyms] [k] prepare_exec_creds 6.00% 1 perf [jbd2] [k] start_this_handle 5.29% 1 perf [kernel.kallsyms] [k] seq_read 4.75% 1 perf [kernel.kallsyms] [k] get_pid_task 4.30% 1 perf [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore # # (For a higher level overview, try: perf report --sort comm,dso) # [root@emilia ~]# Reported-by: Stephane Eranian Acked-by: Stephane Eranian Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 3f437236f193..da2899e8c6f8 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -591,6 +591,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, { struct sort_entry *se; u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; + u64 nr_events; const char *sep = symbol_conf.field_sep; int ret; @@ -599,6 +600,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, if (pair_hists) { period = self->pair ? self->pair->period : 0; + nr_events = self->pair ? self->pair->nr_events : 0; total = pair_hists->stats.total_period; period_sys = self->pair ? self->pair->period_sys : 0; period_us = self->pair ? self->pair->period_us : 0; @@ -606,6 +608,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, period_guest_us = self->pair ? self->pair->period_guest_us : 0; } else { period = self->period; + nr_events = self->nr_events; total = session_total; period_sys = self->period_sys; period_us = self->period_us; @@ -646,9 +649,9 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, if (symbol_conf.show_nr_samples) { if (sep) - ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period); + ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events); else - ret += snprintf(s + ret, size - ret, "%11" PRIu64, period); + ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events); } if (pair_hists) { From 712a4b6049724278121d56aba683151d86c8c35a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Feb 2011 12:18:42 -0200 Subject: [PATCH 4/6] perf record: Delay setting the header writing atexit call While testing the --filter option I noticed that we were writing lots of unneeded stuff to the perf.data header when the filter ioctl fails, so move the atexit(atexit_header) call to after we create the counters successfully. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a4aaadcb4c8b..db4cd1e7b51a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -538,11 +538,6 @@ static int __cmd_record(int argc, const char **argv) if (have_tracepoints(&evsel_list->entries)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); - /* - * perf_session__delete(session) will be called at atexit_header() - */ - atexit(atexit_header); - if (forks) { child_pid = fork(); if (child_pid < 0) { @@ -601,6 +596,11 @@ static int __cmd_record(int argc, const char **argv) perf_session__set_sample_type(session, sample_type); + /* + * perf_session__delete(session) will be called at atexit_header() + */ + atexit(atexit_header); + if (pipe_output) { err = perf_header__write_pipe(output); if (err < 0) From 74cfc17dc1a69c37ce6c8a76c1ce84bcb796eb0e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Feb 2011 14:40:46 -0200 Subject: [PATCH 5/6] perf report: Tell the user when a perf.data file has no samples [root@emilia ~]# perf report --stdio The perf.data file has no samples! [root@emilia ~]# The TUI shows a popup warning message with the same message. Reported-by: Ingo Molnar Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Steven Rostedt Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f9a99a1ce609..dddcc7ea2bec 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -350,6 +350,12 @@ static int __cmd_report(void) perf_session__fprintf_dsos(session, stdout); next = rb_first(&session->hists_tree); + + if (next == NULL) { + ui__warning("The %s file has no samples!\n", input_name); + goto out_delete; + } + while (next) { struct hists *hists; From 668b8788f497b2386402daeca583d6300240d41d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 Feb 2011 15:38:58 -0200 Subject: [PATCH 6/6] perf list: Allow filtering list of events The man page has the details, here are some examples: [root@emilia ~]# perf list *fault* *:*wait* List of pre-defined events (to be used in -e): page-faults OR faults [Software event] minor-faults [Software event] major-faults [Software event] alignment-faults [Software event] emulation-faults [Software event] radeon:radeon_fence_wait_begin [Tracepoint event] radeon:radeon_fence_wait_end [Tracepoint event] writeback:wbc_writeback_wait [Tracepoint event] writeback:wbc_balance_dirty_wait [Tracepoint event] writeback:writeback_congestion_wait [Tracepoint event] writeback:writeback_wait_iff_congested [Tracepoint event] sched:sched_wait_task [Tracepoint event] sched:sched_process_wait [Tracepoint event] sched:sched_stat_wait [Tracepoint event] sched:sched_stat_iowait [Tracepoint event] syscalls:sys_enter_epoll_wait [Tracepoint event] syscalls:sys_exit_epoll_wait [Tracepoint event] syscalls:sys_enter_epoll_pwait [Tracepoint event] syscalls:sys_exit_epoll_pwait [Tracepoint event] syscalls:sys_enter_rt_sigtimedwait [Tracepoint event] syscalls:sys_exit_rt_sigtimedwait [Tracepoint event] syscalls:sys_enter_waitid [Tracepoint event] syscalls:sys_exit_waitid [Tracepoint event] syscalls:sys_enter_wait4 [Tracepoint event] syscalls:sys_exit_wait4 [Tracepoint event] syscalls:sys_enter_waitpid [Tracepoint event] syscalls:sys_exit_waitpid [Tracepoint event] [root@emilia ~]# Suggested-by: Ingo Molnar Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 23 ++++++- tools/perf/builtin-list.c | 43 +++++++++++- tools/perf/util/parse-events.c | 94 +++++++++++++++++++++----- tools/perf/util/parse-events.h | 5 +- 4 files changed, 142 insertions(+), 23 deletions(-) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 399751befeed..7a527f7e9da9 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -8,7 +8,7 @@ perf-list - List all symbolic event types SYNOPSIS -------- [verse] -'perf list' +'perf list' [hw|sw|cache|tracepoint|event_glob] DESCRIPTION ----------- @@ -63,7 +63,26 @@ details. Some of them are referenced in the SEE ALSO section below. OPTIONS ------- -None + +Without options all known events will be listed. + +To limit the list use: + +. 'hw' or 'hardware' to list hardware events such as cache-misses, etc. + +. 'sw' or 'software' to list software events such as context switches, etc. + +. 'cache' or 'hwcache' to list hardware cache events such as L1-dcache-loads, etc. + +. 'tracepoint' to list all tracepoint events, alternatively use + 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, + block, etc. + +. If none of the above is matched, it will apply the supplied glob to all + events, printing the ones that match. + +One or more types can be used at the same time, listing the events for the +types specified. SEE ALSO -------- diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index d88c6961274c..6313b6eb3ebb 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -5,6 +5,7 @@ * * Copyright (C) 2009, Thomas Gleixner * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar + * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo */ #include "builtin.h" @@ -13,9 +14,47 @@ #include "util/parse-events.h" #include "util/cache.h" -int cmd_list(int argc __used, const char **argv __used, const char *prefix __used) +int cmd_list(int argc, const char **argv, const char *prefix __used) { setup_pager(); - print_events(); + + if (argc == 1) + print_events(NULL); + else { + int i; + + for (i = 1; i < argc; ++i) { + if (i > 1) + putchar('\n'); + if (strncmp(argv[i], "tracepoint", 10) == 0) + print_tracepoint_events(NULL, NULL); + else if (strcmp(argv[i], "hw") == 0 || + strcmp(argv[i], "hardware") == 0) + print_events_type(PERF_TYPE_HARDWARE); + else if (strcmp(argv[i], "sw") == 0 || + strcmp(argv[i], "software") == 0) + print_events_type(PERF_TYPE_SOFTWARE); + else if (strcmp(argv[i], "cache") == 0 || + strcmp(argv[i], "hwcache") == 0) + print_hwcache_events(NULL); + else { + char *sep = strchr(argv[i], ':'), *s; + int sep_idx; + + if (sep == NULL) { + print_events(argv[i]); + continue; + } + sep_idx = sep - argv[i]; + s = strdup(argv[i]); + if (s == NULL) + return -1; + + s[sep_idx] = '\0'; + print_tracepoint_events(s, s + sep_idx + 1); + free(s); + } + } + } return 0; } diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 80a3dd5ef573..54a7e2634d58 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -858,7 +858,7 @@ static const char * const event_type_descriptors[] = { * Print the events from /tracing/events */ -static void print_tracepoint_events(void) +void print_tracepoint_events(const char *subsys_glob, const char *event_glob) { DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; @@ -873,6 +873,9 @@ static void print_tracepoint_events(void) return; for_each_subsystem(sys_dir, sys_dirent, sys_next) { + if (subsys_glob != NULL && + !strglobmatch(sys_dirent.d_name, subsys_glob)) + continue; snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_dirent.d_name); @@ -881,6 +884,10 @@ static void print_tracepoint_events(void) continue; for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { + if (event_glob != NULL && + !strglobmatch(evt_dirent.d_name, event_glob)) + continue; + snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent.d_name, evt_dirent.d_name); printf(" %-42s [%s]\n", evt_path, @@ -932,13 +939,61 @@ int is_valid_tracepoint(const char *event_string) return 0; } +void print_events_type(u8 type) +{ + struct event_symbol *syms = event_symbols; + unsigned int i; + char name[64]; + + for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { + if (type != syms->type) + continue; + + if (strlen(syms->alias)) + snprintf(name, sizeof(name), "%s OR %s", + syms->symbol, syms->alias); + else + snprintf(name, sizeof(name), "%s", syms->symbol); + + printf(" %-42s [%s]\n", name, + event_type_descriptors[type]); + } +} + +int print_hwcache_events(const char *event_glob) +{ + unsigned int type, op, i, printed = 0; + + for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { + for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { + /* skip invalid cache type */ + if (!is_cache_op_valid(type, op)) + continue; + + for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { + char *name = event_cache_name(type, op, i); + + if (event_glob != NULL && + !strglobmatch(name, event_glob)) + continue; + + printf(" %-42s [%s]\n", name, + event_type_descriptors[PERF_TYPE_HW_CACHE]); + ++printed; + } + } + } + + return printed; +} + /* * Print the help text for the event symbols: */ -void print_events(void) +void print_events(const char *event_glob) { struct event_symbol *syms = event_symbols; - unsigned int i, type, op, prev_type = -1; + unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; char name[40]; printf("\n"); @@ -947,8 +1002,16 @@ void print_events(void) for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { type = syms->type; - if (type != prev_type) + if (type != prev_type && printed) { printf("\n"); + printed = 0; + ntypes_printed++; + } + + if (event_glob != NULL && + !(strglobmatch(syms->symbol, event_glob) || + (syms->alias && strglobmatch(syms->alias, event_glob)))) + continue; if (strlen(syms->alias)) sprintf(name, "%s OR %s", syms->symbol, syms->alias); @@ -958,22 +1021,17 @@ void print_events(void) event_type_descriptors[type]); prev_type = type; + ++printed; } - printf("\n"); - for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { - for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { - /* skip invalid cache type */ - if (!is_cache_op_valid(type, op)) - continue; - - for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { - printf(" %-42s [%s]\n", - event_cache_name(type, op, i), - event_type_descriptors[PERF_TYPE_HW_CACHE]); - } - } + if (ntypes_printed) { + printed = 0; + printf("\n"); } + print_hwcache_events(event_glob); + + if (event_glob != NULL) + return; printf("\n"); printf(" %-42s [%s]\n", @@ -986,7 +1044,7 @@ void print_events(void) event_type_descriptors[PERF_TYPE_BREAKPOINT]); printf("\n"); - print_tracepoint_events(); + print_tracepoint_events(NULL, NULL); exit(129); } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index cf7e94abb676..212f88e07a9c 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -28,7 +28,10 @@ extern int parse_filter(const struct option *opt, const char *str, int unset); #define EVENTS_HELP_MAX (128*1024) -extern void print_events(void); +void print_events(const char *event_glob); +void print_events_type(u8 type); +void print_tracepoint_events(const char *subsys_glob, const char *event_glob); +int print_hwcache_events(const char *event_glob); extern int is_valid_tracepoint(const char *event_string); extern char debugfs_path[];