From ec52d9765a0f3603c62b4238482bf38897e4d42f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 10:11:48 -0300 Subject: [PATCH 01/12] perf top: Remove redundant perf_top->sym_counter We can get that counter index from perf_top->sym_evsel->idx instead. 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-top.c | 11 ++++++----- tools/perf/util/top.c | 2 +- tools/perf/util/top.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 80c9e062bd5b..4bf6e02c2b2a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -515,24 +515,25 @@ static void handle_keypress(struct perf_session *session, int c) break; case 'E': if (top.evlist->nr_entries > 1) { + int counter; fprintf(stderr, "\nAvailable events:"); list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); - prompt_integer(&top.sym_counter, "Enter details event counter"); + prompt_integer(&counter, "Enter details event counter"); - if (top.sym_counter >= top.evlist->nr_entries) { + if (counter >= top.evlist->nr_entries) { top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); - top.sym_counter = 0; fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); sleep(1); break; } list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) - if (top.sym_evsel->idx == top.sym_counter) + if (top.sym_evsel->idx == counter) break; - } else top.sym_counter = 0; + } else + top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); break; case 'f': prompt_integer(&top.count_filter, "Enter display event count filter"); diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 75cfe4d45119..fcfb77762819 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -171,7 +171,7 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root) { struct sym_entry *syme, *n; float sum_ksamples = 0.0; - int snap = !top->display_weighted ? top->sym_counter : 0, j; + int snap = !top->display_weighted ? top->sym_evsel->idx : 0, j; /* Sort the active symbols */ pthread_mutex_lock(&top->active_symbols_lock); diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 96d1cb78af01..96a78312c719 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -41,7 +41,7 @@ struct perf_top { u64 exact_samples; u64 guest_us_samples, guest_kernel_samples; int print_entries, count_filter, delay_secs; - int display_weighted, freq, rb_entries, sym_counter; + int display_weighted, freq, rb_entries; pid_t target_pid, target_tid; bool hide_kernel_symbols, hide_user_symbols, zero; const char *cpu_list; From 8b8ba4a9a5b04916858f79cee71873f973931649 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 12:38:48 -0300 Subject: [PATCH 02/12] perf top: Remove redundant syme->origin field We can get it from syme->map->dso->kernel (that should be renamed to origin, but leave this for another patch). 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-top.c | 1 - tools/perf/util/top.c | 4 ++-- tools/perf/util/top.h | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4bf6e02c2b2a..4976400a1438 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -782,7 +782,6 @@ static void perf_event__process_sample(const union perf_event *event, if (!syme->skip) { struct perf_evsel *evsel; - syme->origin = origin; evsel = perf_evlist__id2evsel(top.evlist, sample->id); assert(evsel != NULL); syme->count[evsel->idx]++; diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index fcfb77762819..a11f60735a18 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -184,9 +184,9 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root) if (syme->snap_count != 0) { if ((top->hide_user_symbols && - syme->origin == PERF_RECORD_MISC_USER) || + syme->map->dso->kernel == DSO_TYPE_USER) || (top->hide_kernel_symbols && - syme->origin == PERF_RECORD_MISC_KERNEL)) { + syme->map->dso->kernel == DSO_TYPE_KERNEL)) { perf_top__remove_active_sym(top, syme); continue; } diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 96a78312c719..ba111b25e16a 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -17,7 +17,6 @@ struct sym_entry { unsigned long snap_count; double weight; int skip; - u8 origin; struct map *map; unsigned long count[0]; }; From 878b439dccd064d6908800fab0b47bd3c3a87ebb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 13:13:36 -0300 Subject: [PATCH 03/12] perf symbols: Rename dso->origin to dso->symtab_type And the DSO__ORIG_ enum to SYMTAB__, to clarify that this is about from where the symtab was obtained. 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-top.c | 4 +-- tools/perf/util/annotate.c | 2 +- tools/perf/util/symbol.c | 64 +++++++++++++++++++------------------- tools/perf/util/symbol.h | 26 ++++++++-------- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4976400a1438..31ea7a68baa4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -152,7 +152,7 @@ static int parse_source(struct sym_entry *syme) /* * We can't annotate with just /proc/kallsyms */ - if (map->dso->origin == DSO__ORIG_KERNEL) { + if (map->dso->symtab_type == SYMTAB__KALLSYMS) { pr_err("Can't annotate %s: No vmlinux file was found in the " "path\n", sym->name); sleep(1); @@ -769,7 +769,7 @@ static void perf_event__process_sample(const union perf_event *event, struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); pr_err("Can't annotate %s", sym->name); - if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { + if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) { pr_err(": No vmlinux file was found in the path:\n"); machine__fprintf_vmlinux_path(machine, stderr); } else diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0d0830c98cd7..e01af2b1a469 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -294,7 +294,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) free_filename = false; } - if (dso->origin == DSO__ORIG_KERNEL) { + if (dso->symtab_type == SYMTAB__KALLSYMS) { char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; char *build_id_msg = NULL; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 00014e32c288..651dbfe7f4f3 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -207,7 +207,7 @@ struct dso *dso__new(const char *name) dso__set_short_name(self, self->name); for (i = 0; i < MAP__NR_TYPES; ++i) self->symbols[i] = self->symbol_names[i] = RB_ROOT; - self->origin = DSO__ORIG_NOT_FOUND; + self->symtab_type = SYMTAB__NOT_FOUND; self->loaded = 0; self->sorted_by_name = 0; self->has_build_id = 0; @@ -680,9 +680,9 @@ int dso__load_kallsyms(struct dso *self, const char *filename, return -1; if (self->kernel == DSO_TYPE_GUEST_KERNEL) - self->origin = DSO__ORIG_GUEST_KERNEL; + self->symtab_type = SYMTAB__GUEST_KALLSYMS; else - self->origin = DSO__ORIG_KERNEL; + self->symtab_type = SYMTAB__KALLSYMS; return dso__split_kallsyms(self, map, filter); } @@ -1204,7 +1204,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, } curr_map->map_ip = identity__map_ip; curr_map->unmap_ip = identity__map_ip; - curr_dso->origin = self->origin; + curr_dso->symtab_type = self->symtab_type; map_groups__insert(kmap->kmaps, curr_map); dsos__add(&self->node, curr_dso); dso__set_loaded(curr_dso, map->type); @@ -1430,21 +1430,21 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) char dso__symtab_origin(const struct dso *self) { static const char origin[] = { - [DSO__ORIG_KERNEL] = 'k', - [DSO__ORIG_JAVA_JIT] = 'j', - [DSO__ORIG_BUILD_ID_CACHE] = 'B', - [DSO__ORIG_FEDORA] = 'f', - [DSO__ORIG_UBUNTU] = 'u', - [DSO__ORIG_BUILDID] = 'b', - [DSO__ORIG_DSO] = 'd', - [DSO__ORIG_KMODULE] = 'K', - [DSO__ORIG_GUEST_KERNEL] = 'g', - [DSO__ORIG_GUEST_KMODULE] = 'G', + [SYMTAB__KALLSYMS] = 'k', + [SYMTAB__JAVA_JIT] = 'j', + [SYMTAB__BUILD_ID_CACHE] = 'B', + [SYMTAB__FEDORA_DEBUGINFO] = 'f', + [SYMTAB__UBUNTU_DEBUGINFO] = 'u', + [SYMTAB__BUILDID_DEBUGINFO] = 'b', + [SYMTAB__SYSTEM_PATH_DSO] = 'd', + [SYMTAB__SYSTEM_PATH_KMODULE] = 'K', + [SYMTAB__GUEST_KALLSYMS] = 'g', + [SYMTAB__GUEST_KMODULE] = 'G', }; - if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) + if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND) return '!'; - return origin[self->origin]; + return origin[self->symtab_type]; } int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) @@ -1477,8 +1477,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) if (strncmp(self->name, "/tmp/perf-", 10) == 0) { ret = dso__load_perf_map(self, map, filter); - self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : - DSO__ORIG_NOT_FOUND; + self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : + SYMTAB__NOT_FOUND; return ret; } @@ -1486,26 +1486,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) * On the first pass, only load images if they have a full symtab. * Failing that, do a second pass where we accept .dynsym also */ - for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; - self->origin != DSO__ORIG_NOT_FOUND; - self->origin++) { - switch (self->origin) { - case DSO__ORIG_BUILD_ID_CACHE: + for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1; + self->symtab_type != SYMTAB__NOT_FOUND; + self->symtab_type++) { + switch (self->symtab_type) { + case SYMTAB__BUILD_ID_CACHE: /* skip the locally configured cache if a symfs is given */ if (symbol_conf.symfs[0] || (dso__build_id_filename(self, name, size) == NULL)) { continue; } break; - case DSO__ORIG_FEDORA: + case SYMTAB__FEDORA_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s.debug", symbol_conf.symfs, self->long_name); break; - case DSO__ORIG_UBUNTU: + case SYMTAB__UBUNTU_DEBUGINFO: snprintf(name, size, "%s/usr/lib/debug%s", symbol_conf.symfs, self->long_name); break; - case DSO__ORIG_BUILDID: { + case SYMTAB__BUILDID_DEBUGINFO: { char build_id_hex[BUILD_ID_SIZE * 2 + 1]; if (!self->has_build_id) @@ -1519,11 +1519,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) symbol_conf.symfs, build_id_hex, build_id_hex + 2); } break; - case DSO__ORIG_DSO: + case SYMTAB__SYSTEM_PATH_DSO: snprintf(name, size, "%s%s", symbol_conf.symfs, self->long_name); break; - case DSO__ORIG_GUEST_KMODULE: + case SYMTAB__GUEST_KMODULE: if (map->groups && machine) root_dir = machine->root_dir; else @@ -1532,7 +1532,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) root_dir, self->long_name); break; - case DSO__ORIG_KMODULE: + case SYMTAB__SYSTEM_PATH_KMODULE: snprintf(name, size, "%s%s", symbol_conf.symfs, self->long_name); break; @@ -1544,7 +1544,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) */ if (want_symtab) { want_symtab = 0; - self->origin = DSO__ORIG_BUILD_ID_CACHE; + self->symtab_type = SYMTAB__BUILD_ID_CACHE; } else continue; } @@ -1757,9 +1757,9 @@ struct map *machine__new_module(struct machine *self, u64 start, return NULL; if (machine__is_host(self)) - dso->origin = DSO__ORIG_KMODULE; + dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; else - dso->origin = DSO__ORIG_GUEST_KMODULE; + dso->symtab_type = SYMTAB__GUEST_KMODULE; map_groups__insert(&self->kmaps, map); return map; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 4d7ed09fe332..db39c0c63608 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -137,7 +137,7 @@ struct dso { u8 annotate_warned:1; u8 sname_alloc:1; u8 lname_alloc:1; - unsigned char origin; + unsigned char symtab_type; u8 sorted_by_name; u8 loaded; u8 build_id[BUILD_ID_SIZE]; @@ -188,18 +188,18 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp); size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp); size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); -enum dso_origin { - DSO__ORIG_KERNEL = 0, - DSO__ORIG_GUEST_KERNEL, - DSO__ORIG_JAVA_JIT, - DSO__ORIG_BUILD_ID_CACHE, - DSO__ORIG_FEDORA, - DSO__ORIG_UBUNTU, - DSO__ORIG_BUILDID, - DSO__ORIG_DSO, - DSO__ORIG_GUEST_KMODULE, - DSO__ORIG_KMODULE, - DSO__ORIG_NOT_FOUND, +enum symtab_type { + SYMTAB__KALLSYMS = 0, + SYMTAB__GUEST_KALLSYMS, + SYMTAB__JAVA_JIT, + SYMTAB__BUILD_ID_CACHE, + SYMTAB__FEDORA_DEBUGINFO, + SYMTAB__UBUNTU_DEBUGINFO, + SYMTAB__BUILDID_DEBUGINFO, + SYMTAB__SYSTEM_PATH_DSO, + SYMTAB__GUEST_KMODULE, + SYMTAB__SYSTEM_PATH_KMODULE, + SYMTAB__NOT_FOUND, }; char dso__symtab_origin(const struct dso *self); From 171b3be9c42e97cd4530706654242f6a3efb6ac3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 13:36:01 -0300 Subject: [PATCH 04/12] perf symbol: Move sym_entry->skip to symbol->ignore While going thru each of the sym_entry fields looking to reduce it to the set of entries needed when in an active symbols list, 'skip' should really be in symbol, as we set it when loading the symtab. And the space used by the basic symbol allocation remains the same as we had 5 bytes of padding. 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-top.c | 4 ++-- tools/perf/util/symbol.h | 5 +++++ tools/perf/util/top.h | 1 - 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31ea7a68baa4..70f1075cc5b0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -676,7 +676,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) for (i = 0; skip_symbols[i]; i++) { if (!strcmp(skip_symbols[i], name)) { - syme->skip = 1; + sym->ignore = true; break; } } @@ -779,7 +779,7 @@ static void perf_event__process_sample(const union perf_event *event, } syme = symbol__priv(al.sym); - if (!syme->skip) { + if (!al.sym->ignore) { struct perf_evsel *evsel; evsel = perf_evlist__id2evsel(top.evlist, sample->id); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index db39c0c63608..713b0b40cc4a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -48,12 +48,17 @@ char *strxfrchar(char *s, char from, char to); #define BUILD_ID_SIZE 20 +/** struct symbol - symtab entry + * + * @ignore - resolvable but tools ignore it (e.g. idle routines) + */ struct symbol { struct rb_node rb_node; u64 start; u64 end; u16 namelen; u8 binding; + bool ignore; char name[0]; }; diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index ba111b25e16a..bfbf95bcc603 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -16,7 +16,6 @@ struct sym_entry { struct list_head node; unsigned long snap_count; double weight; - int skip; struct map *map; unsigned long count[0]; }; From cfd748ae066e776d45bdce550b47cd00c67d55de Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Mon, 14 Mar 2011 16:40:30 +0100 Subject: [PATCH 05/12] perf stat: Provide support for filters Now the --filter option is usable with perf stat too. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <1300117230-8404-1-git-send-email-fweisbec@gmail.com> Signed-off-by: Frederic Weisbecker Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 21c025222496..e2109f9b43eb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -333,6 +333,12 @@ static int run_perf_stat(int argc __used, const char **argv) } } + if (perf_evlist__set_filters(evsel_list)) { + error("failed to set filter with %d (%s)\n", errno, + strerror(errno)); + return -1; + } + /* * Enable counters and exec the command: */ @@ -634,6 +640,8 @@ static const struct option options[] = { OPT_CALLBACK('e', "event", &evsel_list, "event", "event selector. use 'perf list' to list available events", parse_events), + OPT_CALLBACK(0, "filter", &evsel_list, "filter", + "event filter", parse_filter), OPT_BOOLEAN('i', "no-inherit", &no_inherit, "child tasks do not inherit counters"), OPT_INTEGER('p', "pid", &target_pid, From be6d842a65babc54e2b204b382df2529e304be48 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 9 Mar 2011 22:23:23 -0700 Subject: [PATCH 06/12] perf script: Change process_event prototype Prepare for handling of samples for any event type. Acked-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner LKML-Reference: <1299734608-5223-2-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 25 ++++++++++++------- .../util/scripting-engines/trace-event-perl.c | 11 +++++--- .../scripting-engines/trace-event-python.c | 11 +++++--- tools/perf/util/trace-event-scripting.c | 9 +++---- tools/perf/util/trace-event.h | 7 ++++-- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 5f40df635dcb..b2bdd5534026 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -20,6 +20,20 @@ static u64 last_timestamp; static u64 nr_unordered; extern const struct option record_options[]; +static void process_event(union perf_event *event __unused, + struct perf_sample *sample, + struct perf_session *session __unused, + struct thread *thread) +{ + /* + * FIXME: better resolve from pid from the struct trace_entry + * field, although it should be the same than this perf + * event pid + */ + print_event(sample->cpu, sample->raw_data, sample->raw_size, + sample->time, thread->comm); +} + static int default_start_script(const char *script __unused, int argc __unused, const char **argv __unused) @@ -40,7 +54,7 @@ static int default_generate_script(const char *outfile __unused) static struct scripting_ops default_scripting_ops = { .start_script = default_start_script, .stop_script = default_stop_script, - .process_event = print_event, + .process_event = process_event, .generate_script = default_generate_script, }; @@ -86,14 +100,7 @@ static int process_sample_event(union perf_event *event, last_timestamp = sample->time; return 0; } - /* - * FIXME: better resolve from pid from the struct trace_entry - * field, although it should be the same than this perf - * event pid - */ - scripting_ops->process_event(sample->cpu, sample->raw_data, - sample->raw_size, - sample->time, thread->comm); + scripting_ops->process_event(event, sample, session, thread); } session->hists.stats.total_period += sample->period; diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 93680818e244..621427212e86 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -245,9 +245,10 @@ static inline struct event *find_cache_event(int type) return event; } -static void perl_process_event(int cpu, void *data, - int size __unused, - unsigned long long nsecs, char *comm) +static void perl_process_event(union perf_event *pevent __unused, + struct perf_sample *sample, + struct perf_session *session __unused, + struct thread *thread) { struct format_field *field; static char handler[256]; @@ -256,6 +257,10 @@ static void perl_process_event(int cpu, void *data, struct event *event; int type; int pid; + int cpu = sample->cpu; + void *data = sample->raw_data; + unsigned long long nsecs = sample->time; + char *comm = thread->comm; dSP; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 2040b8538527..1b85d6055159 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -204,9 +204,10 @@ static inline struct event *find_cache_event(int type) return event; } -static void python_process_event(int cpu, void *data, - int size __unused, - unsigned long long nsecs, char *comm) +static void python_process_event(union perf_event *pevent __unused, + struct perf_sample *sample, + struct perf_session *session __unused, + struct thread *thread) { PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; static char handler_name[256]; @@ -217,6 +218,10 @@ static void python_process_event(int cpu, void *data, unsigned n = 0; int type; int pid; + int cpu = sample->cpu; + void *data = sample->raw_data; + unsigned long long nsecs = sample->time; + char *comm = thread->comm; t = PyTuple_New(MAX_FIELDS); if (!t) diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index f7af2fca965d..66f4b78737ab 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -36,11 +36,10 @@ static int stop_script_unsupported(void) return 0; } -static void process_event_unsupported(int cpu __unused, - void *data __unused, - int size __unused, - unsigned long long nsecs __unused, - char *comm __unused) +static void process_event_unsupported(union perf_event *event __unused, + struct perf_sample *sample __unused, + struct perf_session *session __unused, + struct thread *thread __unused) { } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index b5f12ca24d99..5f7b5139c321 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -3,6 +3,7 @@ #include #include "parse-events.h" +#include "session.h" #define __unused __attribute__((unused)) @@ -278,8 +279,10 @@ struct scripting_ops { const char *name; int (*start_script) (const char *script, int argc, const char **argv); int (*stop_script) (void); - void (*process_event) (int cpu, void *data, int size, - unsigned long long nsecs, char *comm); + void (*process_event) (union perf_event *event, + struct perf_sample *sample, + struct perf_session *session, + struct thread *thread); int (*generate_script) (const char *outfile); }; From 2ee7a49f935b19f7daf0a110800488acd2479cba Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 9 Mar 2011 22:23:24 -0700 Subject: [PATCH 07/12] perf tracing: Remove print_graph_cpu and print_graph_proc from trace-event-parse Next patch moves printing of 'common' data into perf-script which removes the need for these functions. Acked-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner LKML-Reference: <1299734608-5223-3-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trace-event-parse.c | 65 +---------------------------- 1 file changed, 2 insertions(+), 63 deletions(-) diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index d8e622dd738a..dd5f058292d8 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -2648,63 +2648,8 @@ static void print_lat_fmt(void *data, int size __unused) printf("%d", lock_depth); } -/* taken from Linux, written by Frederic Weisbecker */ -static void print_graph_cpu(int cpu) -{ - int i; - int log10_this = log10_cpu(cpu); - int log10_all = log10_cpu(cpus); - - - /* - * Start with a space character - to make it stand out - * to the right a bit when trace output is pasted into - * email: - */ - printf(" "); - - /* - * Tricky - we space the CPU field according to the max - * number of online CPUs. On a 2-cpu system it would take - * a maximum of 1 digit - on a 128 cpu system it would - * take up to 3 digits: - */ - for (i = 0; i < log10_all - log10_this; i++) - printf(" "); - - printf("%d) ", cpu); -} - -#define TRACE_GRAPH_PROCINFO_LENGTH 14 #define TRACE_GRAPH_INDENT 2 -static void print_graph_proc(int pid, const char *comm) -{ - /* sign + log10(MAX_INT) + '\0' */ - char pid_str[11]; - int spaces = 0; - int len; - int i; - - sprintf(pid_str, "%d", pid); - - /* 1 stands for the "-" character */ - len = strlen(comm) + strlen(pid_str) + 1; - - if (len < TRACE_GRAPH_PROCINFO_LENGTH) - spaces = TRACE_GRAPH_PROCINFO_LENGTH - len; - - /* First spaces to align center */ - for (i = 0; i < spaces / 2; i++) - printf(" "); - - printf("%s-%s", comm, pid_str); - - /* Last spaces to align center */ - for (i = 0; i < spaces - (spaces / 2); i++) - printf(" "); -} - static struct record * get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func, struct record *next) @@ -2876,7 +2821,7 @@ static void print_graph_nested(struct event *event, void *data) static void pretty_print_func_ent(void *data, int size, struct event *event, - int cpu, int pid, const char *comm, + int cpu, int pid, const char *comm __unused, unsigned long secs, unsigned long usecs) { struct format_field *field; @@ -2886,9 +2831,6 @@ pretty_print_func_ent(void *data, int size, struct event *event, printf("%5lu.%06lu | ", secs, usecs); - print_graph_cpu(cpu); - print_graph_proc(pid, comm); - printf(" | "); if (latency_format) { @@ -2924,7 +2866,7 @@ pretty_print_func_ent(void *data, int size, struct event *event, static void pretty_print_func_ret(void *data, int size __unused, struct event *event, - int cpu, int pid, const char *comm, + int cpu __unused, int pid __unused, const char *comm __unused, unsigned long secs, unsigned long usecs) { unsigned long long rettime, calltime; @@ -2934,9 +2876,6 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event, printf("%5lu.%06lu | ", secs, usecs); - print_graph_cpu(cpu); - print_graph_proc(pid, comm); - printf(" | "); if (latency_format) { From c70c94b47405d2c94df19c16273daf1f5fb9193d Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 9 Mar 2011 22:23:25 -0700 Subject: [PATCH 08/12] perf script: Move printing of 'common' data from print_event and rename This change does impact output: latency data is trace specific and is now printed after the common data - comm, tid, cpu, time and event name. Acked-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner LKML-Reference: <1299734608-5223-4-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 38 +++++++++++++++++----- tools/perf/util/trace-event-parse.c | 49 ++++++----------------------- tools/perf/util/trace-event.h | 3 +- 3 files changed, 42 insertions(+), 48 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b2bdd5534026..0a79da21df23 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -20,18 +20,42 @@ static u64 last_timestamp; static u64 nr_unordered; extern const struct option record_options[]; +static void print_sample_start(struct perf_sample *sample, + struct thread *thread) +{ + int type; + struct event *event; + const char *evname = NULL; + unsigned long secs; + unsigned long usecs; + unsigned long long nsecs = sample->time; + + if (latency_format) + printf("%8.8s-%-5d %3d", thread->comm, sample->tid, sample->cpu); + else + printf("%16s-%-5d [%03d]", thread->comm, sample->tid, sample->cpu); + + secs = nsecs / NSECS_PER_SEC; + nsecs -= secs * NSECS_PER_SEC; + usecs = nsecs / NSECS_PER_USEC; + printf(" %5lu.%06lu: ", secs, usecs); + + type = trace_parse_common_type(sample->raw_data); + event = trace_find_event(type); + if (event) + evname = event->name; + + printf("%s: ", evname ? evname : "(unknown)"); +} + static void process_event(union perf_event *event __unused, struct perf_sample *sample, struct perf_session *session __unused, struct thread *thread) { - /* - * FIXME: better resolve from pid from the struct trace_entry - * field, although it should be the same than this perf - * event pid - */ - print_event(sample->cpu, sample->raw_data, sample->raw_size, - sample->time, thread->comm); + print_sample_start(sample, thread); + print_trace_event(sample->cpu, sample->raw_data, sample->raw_size); + printf("\n"); } static int default_start_script(const char *script __unused, diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index dd5f058292d8..0a7ed5b5e281 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -2643,9 +2643,9 @@ static void print_lat_fmt(void *data, int size __unused) printf("."); if (lock_depth < 0) - printf("."); + printf(". "); else - printf("%d", lock_depth); + printf("%d ", lock_depth); } #define TRACE_GRAPH_INDENT 2 @@ -2821,18 +2821,13 @@ static void print_graph_nested(struct event *event, void *data) static void pretty_print_func_ent(void *data, int size, struct event *event, - int cpu, int pid, const char *comm __unused, - unsigned long secs, unsigned long usecs) + int cpu, int pid) { struct format_field *field; struct record *rec; void *copy_data; unsigned long val; - printf("%5lu.%06lu | ", secs, usecs); - - printf(" | "); - if (latency_format) { print_lat_fmt(data, size); printf(" | "); @@ -2865,19 +2860,13 @@ pretty_print_func_ent(void *data, int size, struct event *event, } static void -pretty_print_func_ret(void *data, int size __unused, struct event *event, - int cpu __unused, int pid __unused, const char *comm __unused, - unsigned long secs, unsigned long usecs) +pretty_print_func_ret(void *data, int size __unused, struct event *event) { unsigned long long rettime, calltime; unsigned long long duration, depth; struct format_field *field; int i; - printf("%5lu.%06lu | ", secs, usecs); - - printf(" | "); - if (latency_format) { print_lat_fmt(data, size); printf(" | "); @@ -2915,31 +2904,21 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event, static void pretty_print_func_graph(void *data, int size, struct event *event, - int cpu, int pid, const char *comm, - unsigned long secs, unsigned long usecs) + int cpu, int pid) { if (event->flags & EVENT_FL_ISFUNCENT) - pretty_print_func_ent(data, size, event, - cpu, pid, comm, secs, usecs); + pretty_print_func_ent(data, size, event, cpu, pid); else if (event->flags & EVENT_FL_ISFUNCRET) - pretty_print_func_ret(data, size, event, - cpu, pid, comm, secs, usecs); + pretty_print_func_ret(data, size, event); printf("\n"); } -void print_event(int cpu, void *data, int size, unsigned long long nsecs, - char *comm) +void print_trace_event(int cpu, void *data, int size) { struct event *event; - unsigned long secs; - unsigned long usecs; int type; int pid; - secs = nsecs / NSECS_PER_SEC; - nsecs -= secs * NSECS_PER_SEC; - usecs = nsecs / NSECS_PER_USEC; - type = trace_parse_common_type(data); event = trace_find_event(type); @@ -2951,17 +2930,10 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, pid = trace_parse_common_pid(data); if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET)) - return pretty_print_func_graph(data, size, event, cpu, - pid, comm, secs, usecs); + return pretty_print_func_graph(data, size, event, cpu, pid); - if (latency_format) { - printf("%8.8s-%-5d %3d", - comm, pid, cpu); + if (latency_format) print_lat_fmt(data, size); - } else - printf("%16s-%-5d [%03d]", comm, pid, cpu); - - printf(" %5lu.%06lu: %s: ", secs, usecs, event->name); if (event->flags & EVENT_FL_FAILED) { printf("EVENT '%s' FAILED TO PARSE\n", @@ -2970,7 +2942,6 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs, } pretty_print(data, size, event); - printf("\n"); } static void print_fields(struct print_flag_sym *field) diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 5f7b5139c321..b04da5722437 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -177,8 +177,7 @@ void print_printk(void); int parse_ftrace_file(char *buf, unsigned long size); int parse_event_file(char *buf, unsigned long size, char *sys); -void print_event(int cpu, void *data, int size, unsigned long long nsecs, - char *comm); +void print_trace_event(int cpu, void *data, int size); extern int file_bigendian; extern int host_bigendian; From 745f43e3433a7939bd9c351c8106e0c1db2044c6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 9 Mar 2011 22:23:26 -0700 Subject: [PATCH 09/12] perf script: Support custom field selection for output Allow a user to select which fields to print to stdout for event data. Options include comm (command name), tid (thread id), pid (process id), time (perf timestamp), cpu, event (for event name), and trace (for trace data). Default is set to maintain compatibility with current output; this feature does alter output format slightly -- no '-' between command and pid/tid. Thanks to Frederic Weisbecker for detailed suggestions on this approach. Examples (output compressed) 1. trace, default format perf record -ga -e sched:sched_switch perf script swapper 0 [000] 537.037184: sched_switch: prev_comm=swapper prev_pid=0... sshd 1675 [000] 537.037309: sched_switch: prev_comm=sshd prev_pid=1675... netstat 1692 [001] 537.038664: sched_switch: prev_comm=netstat prev_pid=1692... 2. trace, custom format perf record -ga -e sched:sched_switch perf script -f comm,pid,time,trace <--- omitting cpu and event name swapper 0 537.037184: prev_comm=swapper prev_pid=0 prev_prio=120 ... sshd 1675 537.037309: prev_comm=sshd prev_pid=1675 prev_prio=120 ... netstat 1692 537.038664: prev_comm=netstat prev_pid=1692 prev_prio=120 ... Acked-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner LKML-Reference: <1299734608-5223-5-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 5 + tools/perf/builtin-script.c | 141 ++++++++++++++++++++--- 2 files changed, 130 insertions(+), 16 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 29ad94293cd2..b73cf589c109 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -112,6 +112,11 @@ OPTIONS --debug-mode:: Do various checks like samples ordering and lost events. +-f:: +--fields + Comma separated list of fields to print. Options are: + comm, tid, pid, time, cpu, event, trace + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-script-perl[1], diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 0a79da21df23..c046e6e8600a 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -20,6 +20,38 @@ static u64 last_timestamp; static u64 nr_unordered; extern const struct option record_options[]; +enum perf_output_field { + PERF_OUTPUT_COMM = 1U << 0, + PERF_OUTPUT_TID = 1U << 1, + PERF_OUTPUT_PID = 1U << 2, + PERF_OUTPUT_TIME = 1U << 3, + PERF_OUTPUT_CPU = 1U << 4, + PERF_OUTPUT_EVNAME = 1U << 5, + PERF_OUTPUT_TRACE = 1U << 6, +}; + +struct output_option { + const char *str; + enum perf_output_field field; +} all_output_options[] = { + {.str = "comm", .field = PERF_OUTPUT_COMM}, + {.str = "tid", .field = PERF_OUTPUT_TID}, + {.str = "pid", .field = PERF_OUTPUT_PID}, + {.str = "time", .field = PERF_OUTPUT_TIME}, + {.str = "cpu", .field = PERF_OUTPUT_CPU}, + {.str = "event", .field = PERF_OUTPUT_EVNAME}, + {.str = "trace", .field = PERF_OUTPUT_TRACE}, +}; + +/* default set to maintain compatibility with current format */ +static u64 output_fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ + PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE; + +static bool output_set_by_user; + +#define PRINT_FIELD(x) (output_fields & PERF_OUTPUT_##x) + static void print_sample_start(struct perf_sample *sample, struct thread *thread) { @@ -28,24 +60,45 @@ static void print_sample_start(struct perf_sample *sample, const char *evname = NULL; unsigned long secs; unsigned long usecs; - unsigned long long nsecs = sample->time; + unsigned long long nsecs; - if (latency_format) - printf("%8.8s-%-5d %3d", thread->comm, sample->tid, sample->cpu); - else - printf("%16s-%-5d [%03d]", thread->comm, sample->tid, sample->cpu); + if (PRINT_FIELD(COMM)) { + if (latency_format) + printf("%8.8s ", thread->comm); + else + printf("%16s ", thread->comm); + } - secs = nsecs / NSECS_PER_SEC; - nsecs -= secs * NSECS_PER_SEC; - usecs = nsecs / NSECS_PER_USEC; - printf(" %5lu.%06lu: ", secs, usecs); + if (PRINT_FIELD(PID) && PRINT_FIELD(TID)) + printf("%5d/%-5d ", sample->pid, sample->tid); + else if (PRINT_FIELD(PID)) + printf("%5d ", sample->pid); + else if (PRINT_FIELD(TID)) + printf("%5d ", sample->tid); - type = trace_parse_common_type(sample->raw_data); - event = trace_find_event(type); - if (event) - evname = event->name; + if (PRINT_FIELD(CPU)) { + if (latency_format) + printf("%3d ", sample->cpu); + else + printf("[%03d] ", sample->cpu); + } - printf("%s: ", evname ? evname : "(unknown)"); + if (PRINT_FIELD(TIME)) { + nsecs = sample->time; + secs = nsecs / NSECS_PER_SEC; + nsecs -= secs * NSECS_PER_SEC; + usecs = nsecs / NSECS_PER_USEC; + printf("%5lu.%06lu: ", secs, usecs); + } + + if (PRINT_FIELD(EVNAME)) { + type = trace_parse_common_type(sample->raw_data); + event = trace_find_event(type); + if (event) + evname = event->name; + + printf("%s: ", evname ? evname : "(unknown)"); + } } static void process_event(union perf_event *event __unused, @@ -54,7 +107,11 @@ static void process_event(union perf_event *event __unused, struct thread *thread) { print_sample_start(sample, thread); - print_trace_event(sample->cpu, sample->raw_data, sample->raw_size); + + if (PRINT_FIELD(TRACE)) + print_trace_event(sample->cpu, sample->raw_data, + sample->raw_size); + printf("\n"); } @@ -311,6 +368,48 @@ static int parse_scriptname(const struct option *opt __used, return 0; } +static int parse_output_fields(const struct option *opt __used, + const char *arg, int unset __used) +{ + char *tok; + int i, imax = sizeof(all_output_options) / sizeof(struct output_option); + int rc = 0; + char *str = strdup(arg); + + if (!str) + return -ENOMEM; + + tok = strtok(str, ","); + if (!tok) { + fprintf(stderr, "Invalid field string."); + return -EINVAL; + } + + output_fields = 0; + while (1) { + for (i = 0; i < imax; ++i) { + if (strcmp(tok, all_output_options[i].str) == 0) { + output_fields |= all_output_options[i].field; + break; + } + } + if (i == imax) { + fprintf(stderr, "Invalid field requested."); + rc = -EINVAL; + break; + } + + tok = strtok(NULL, ","); + if (!tok) + break; + } + + output_set_by_user = true; + + free(str); + return rc; +} + /* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */ static int is_directory(const char *base_path, const struct dirent *dent) { @@ -623,6 +722,9 @@ static const struct option options[] = { "input file name"), OPT_BOOLEAN('d', "debug-mode", &debug_mode, "do various checks like samples ordering and lost events"), + OPT_CALLBACK('f', "fields", NULL, "str", + "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace", + parse_output_fields), OPT_END() }; @@ -809,8 +911,15 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (generate_script_lang) { struct stat perf_stat; + int input; - int input = open(input_name, O_RDONLY); + if (output_set_by_user) { + fprintf(stderr, + "custom fields not supported for generated scripts"); + return -1; + } + + input = open(input_name, O_RDONLY); if (input < 0) { perror("failed to open file"); exit(-1); From c0230b2bfbd16e42d937c34aed99e5d6493eb5e4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 9 Mar 2011 22:23:27 -0700 Subject: [PATCH 10/12] perf script: Add support for dumping symbols Add option to dump symbols found in events. e.g., perf script -f comm,pid,tid,time,trace,sym swapper 0/0 537.037184: prev_comm=swapper prev_pid=0 prev_prio=120... ffffffff81030350 perf_trace_sched_switch ([kernel.kallsyms]) ffffffff81382ac5 schedule ([kernel.kallsyms]) ffffffff8100134a cpu_idle ([kernel.kallsyms]) ffffffff81370b39 rest_init ([kernel.kallsyms]) ffffffff81696c23 start_kernel ([kernel.kallsyms].init.text) ffffffff816962af x86_64_start_reservations ([kernel.kallsyms].init.text) ffffffff816963b9 x86_64_start_kernel ([kernel.kallsyms].init.text) sshd 1675/1675 537.037309: prev_comm=sshd prev_pid=1675 prev_prio=120... ffffffff81030350 perf_trace_sched_switch ([kernel.kallsyms]) ffffffff81382ac5 schedule ([kernel.kallsyms]) ffffffff813837aa schedule_hrtimeout_range_clock ([kernel.kallsyms]) ffffffff81383886 schedule_hrtimeout_range ([kernel.kallsyms]) ffffffff8110c4f9 poll_schedule_timeout ([kernel.kallsyms]) ffffffff8110cd20 do_select ([kernel.kallsyms]) ffffffff8110ced8 core_sys_select ([kernel.kallsyms]) ffffffff8110d00d sys_select ([kernel.kallsyms]) ffffffff81002bc2 system_call ([kernel.kallsyms]) 7f1647e56e93 __GI_select (/lib64/libc-2.12.90.so) netstat 1692/1692 537.038664: prev_comm=netstat prev_pid=1692 prev_prio=... ffffffff81030350 perf_trace_sched_switch ([kernel.kallsyms]) ffffffff81382ac5 schedule ([kernel.kallsyms]) ffffffff81002c3a sysret_careful ([kernel.kallsyms]) 7f7a6cd1b210 __GI___libc_read (/lib64/libc-2.12.90.so) Acked-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner LKML-Reference: <1299734608-5223-6-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 16 ++++++- tools/perf/builtin-script.c | 31 +++++++++++- tools/perf/util/session.c | 61 ++++++++++++++++++++++++ tools/perf/util/session.h | 4 ++ 4 files changed, 110 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index b73cf589c109..c64118a4de49 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -115,7 +115,21 @@ OPTIONS -f:: --fields Comma separated list of fields to print. Options are: - comm, tid, pid, time, cpu, event, trace + comm, tid, pid, time, cpu, event, trace, sym + +-k:: +--vmlinux=:: + vmlinux pathname + +--kallsyms=:: + kallsyms pathname + +--symfs=:: + Look for files with symbols relative to this directory. + +-G:: +--hide-call-graph:: + When printing symbols do not display call chain. SEE ALSO -------- diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c046e6e8600a..b45b09c13f7a 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -19,6 +19,7 @@ static bool debug_mode; static u64 last_timestamp; static u64 nr_unordered; extern const struct option record_options[]; +static bool no_callchain; enum perf_output_field { PERF_OUTPUT_COMM = 1U << 0, @@ -28,6 +29,7 @@ enum perf_output_field { PERF_OUTPUT_CPU = 1U << 4, PERF_OUTPUT_EVNAME = 1U << 5, PERF_OUTPUT_TRACE = 1U << 6, + PERF_OUTPUT_SYM = 1U << 7, }; struct output_option { @@ -41,6 +43,7 @@ struct output_option { {.str = "cpu", .field = PERF_OUTPUT_CPU}, {.str = "event", .field = PERF_OUTPUT_EVNAME}, {.str = "trace", .field = PERF_OUTPUT_TRACE}, + {.str = "sym", .field = PERF_OUTPUT_SYM}, }; /* default set to maintain compatibility with current format */ @@ -65,6 +68,8 @@ static void print_sample_start(struct perf_sample *sample, if (PRINT_FIELD(COMM)) { if (latency_format) printf("%8.8s ", thread->comm); + else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain) + printf("%s ", thread->comm); else printf("%16s ", thread->comm); } @@ -112,6 +117,14 @@ static void process_event(union perf_event *event __unused, print_trace_event(sample->cpu, sample->raw_data, sample->raw_size); + if (PRINT_FIELD(SYM)) { + if (!symbol_conf.use_callchain) + printf(" "); + else + printf("\n"); + perf_session__print_symbols(event, sample, session); + } + printf("\n"); } @@ -190,7 +203,10 @@ static int process_sample_event(union perf_event *event, static struct perf_event_ops event_ops = { .sample = process_sample_event, + .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, + .exit = perf_event__process_task, + .fork = perf_event__process_task, .attr = perf_event__process_attr, .event_type = perf_event__process_event_type, .tracing_data = perf_event__process_tracing_data, @@ -722,8 +738,16 @@ static const struct option options[] = { "input file name"), OPT_BOOLEAN('d', "debug-mode", &debug_mode, "do various checks like samples ordering and lost events"), + OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, + "file", "vmlinux pathname"), + OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, + "file", "kallsyms pathname"), + OPT_BOOLEAN('G', "hide-call-graph", &no_callchain, + "When printing symbols do not display call chain"), + OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", + "Look for files with symbols relative to this directory"), OPT_CALLBACK('f', "fields", NULL, "str", - "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace", + "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace,sym", parse_output_fields), OPT_END() @@ -905,6 +929,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (session == NULL) return -ENOMEM; + if (!no_callchain && (session->sample_type & PERF_SAMPLE_CALLCHAIN)) + symbol_conf.use_callchain = true; + else + symbol_conf.use_callchain = false; + if (strcmp(input_name, "-") && !perf_session__has_traces(session, "record -R")) return -EINVAL; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f26639fa0fb3..c68cf40764f9 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1134,3 +1134,64 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) return ret; } + +void perf_session__print_symbols(union perf_event *event, + struct perf_sample *sample, + struct perf_session *session) +{ + struct addr_location al; + const char *symname, *dsoname; + struct callchain_cursor *cursor = &session->callchain_cursor; + struct callchain_cursor_node *node; + + if (perf_event__preprocess_sample(event, session, &al, sample, + NULL) < 0) { + error("problem processing %d event, skipping it.\n", + event->header.type); + return; + } + + if (symbol_conf.use_callchain && sample->callchain) { + + if (perf_session__resolve_callchain(session, al.thread, + sample->callchain, NULL) != 0) { + if (verbose) + error("Failed to resolve callchain. Skipping\n"); + return; + } + callchain_cursor_commit(cursor); + + while (1) { + node = callchain_cursor_current(cursor); + if (!node) + break; + + if (node->sym && node->sym->name) + symname = node->sym->name; + else + symname = ""; + + if (node->map && node->map->dso && node->map->dso->name) + dsoname = node->map->dso->name; + else + dsoname = ""; + + printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname); + + callchain_cursor_advance(cursor); + } + + } else { + if (al.sym && al.sym->name) + symname = al.sym->name; + else + symname = ""; + + if (al.map && al.map->dso && al.map->dso->name) + dsoname = al.map->dso->name; + else + dsoname = ""; + + printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname); + } +} diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b5b148b0aaca..0b3c9afecaa9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -159,4 +159,8 @@ static inline int perf_session__parse_sample(struct perf_session *session, session->sample_id_all, sample); } +void perf_session__print_symbols(union perf_event *event, + struct perf_sample *sample, + struct perf_session *session); + #endif /* __PERF_SESSION_H */ From 1424dc96807909438282663079adc7f27c10b4a5 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 9 Mar 2011 22:23:28 -0700 Subject: [PATCH 11/12] perf script: Add support for H/W and S/W events Custom fields set for each type by prepending field argument with type. For file with multiple event types (e.g., trace and S/W) display of an event type suppressed by setting output fields to "". e.g., perf record -ga -e sched:sched_switch -e cpu-clock -c 10000000 -R -- sleep 1 perf script openssl 11496 [000] 9711.807107: cpu-clock-msecs: ffffffff810c22dc arch_local_irq_restore ([kernel.kallsyms]) ffffffff810c518c __alloc_pages_nodemask ([kernel.kallsyms]) ffffffff810297b2 pte_alloc_one ([kernel.kallsyms]) ffffffff810d8b98 __pte_alloc ([kernel.kallsyms]) ffffffff810daf07 handle_mm_fault ([kernel.kallsyms]) ffffffff8138763a do_page_fault ([kernel.kallsyms]) ffffffff81384a65 page_fault ([kernel.kallsyms]) 7f6130507d70 asn1_check_tlen (/lib64/libcrypto.so.1.0.0c) 0 () openssl 11496 [000] 9711.808042: sched_switch: prev_comm=openssl ... kworker/0:0 4 [000] 9711.808067: sched_switch: prev_comm=kworker/... swapper 0 [001] 9711.808090: sched_switch: prev_comm=kworker/... sshd 11451 [001] 9711.808185: sched_switch: prev_comm=sshd pre... swapper 0 [001] 9711.816155: cpu-clock-msecs: ffffffff81023609 native_safe_halt ([kernel.kallsyms]) ffffffff8100132a cpu_idle ([kernel.kallsyms]) ffffffff8137cf9b start_secondary ([kernel.kallsyms]) openssl 11496 [000] 9711.817104: cpu-clock-msecs: 7f61304ad723 AES_cbc_encrypt (/lib64/libcrypto.so.1.0.0c) 7fff3402f950 () 12f0debc9a785634 () swapper 0 [001] 9711.826155: cpu-clock-msecs: ffffffff81023609 native_safe_halt ([kernel.kallsyms]) ffffffff8100132a cpu_idle ([kernel.kallsyms]) ffffffff8137cf9b start_secondary ([kernel.kallsyms]) To suppress trace events within the file and use default output for S/W events: perf script -f trace: or to suppress S/W events and do default display for trace events: perf script -f sw: Custom field selections: perf script -f sw:comm,tid,time -f trace:time,trace openssl 11496 9711.797162: swapper 0 9711.807071: openssl 11496 9711.807107: 9711.808042: prev_comm=openssl prev_pid=11496 prev_prio=120 prev_state=R ... 9711.808067: prev_comm=kworker/0:0 prev_pid=4 prev_prio=120 prev_state=S ... 9711.808090: prev_comm=kworker/0:0 prev_pid=0 prev_prio=120 prev_state=R ... 9711.808185: prev_comm=sshd prev_pid=11451 prev_prio=120 prev_state=S ==>... swapper 0 9711.816155: openssl 11496 9711.817104: swapper 0 9711.826155: Acked-by: Frederic Weisbecker Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner LKML-Reference: <1299734608-5223-7-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 5 +- tools/perf/builtin-script.c | 155 ++++++++++++++++++----- tools/perf/util/parse-events.c | 22 ++++ tools/perf/util/parse-events.h | 1 + 4 files changed, 147 insertions(+), 36 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index c64118a4de49..66f040b30729 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -115,7 +115,10 @@ OPTIONS -f:: --fields Comma separated list of fields to print. Options are: - comm, tid, pid, time, cpu, event, trace, sym + comm, tid, pid, time, cpu, event, trace, sym. Field + list must be prepended with the type, trace, sw or hw, + to indicate to which event type the field list applies. + e.g., -f sw:comm,tid,time,sym and -f trace:time,cpu,trace -k:: --vmlinux=:: diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b45b09c13f7a..9f5fc5492141 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -12,6 +12,8 @@ #include "util/trace-event.h" #include "util/parse-options.h" #include "util/util.h" +#include "util/evlist.h" +#include "util/evsel.h" static char const *script_name; static char const *generate_script_lang; @@ -47,16 +49,65 @@ struct output_option { }; /* default set to maintain compatibility with current format */ -static u64 output_fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ - PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ - PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE; +static u64 output_fields[PERF_TYPE_MAX] = { + [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ + PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, + + [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ + PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, + + [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \ + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \ + PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, +}; static bool output_set_by_user; -#define PRINT_FIELD(x) (output_fields & PERF_OUTPUT_##x) +#define PRINT_FIELD(x) (output_fields[attr->type] & PERF_OUTPUT_##x) + +static int perf_session__check_attr(struct perf_session *session, + struct perf_event_attr *attr) +{ + if (PRINT_FIELD(TRACE) && + !perf_session__has_traces(session, "record -R")) + return -EINVAL; + + if (PRINT_FIELD(SYM)) { + if (!(session->sample_type & PERF_SAMPLE_IP)) { + pr_err("Samples do not contain IP data.\n"); + return -EINVAL; + } + if (!no_callchain && + !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) + symbol_conf.use_callchain = false; + } + + if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && + !(session->sample_type & PERF_SAMPLE_TID)) { + pr_err("Samples do not contain TID/PID data.\n"); + return -EINVAL; + } + + if (PRINT_FIELD(TIME) && + !(session->sample_type & PERF_SAMPLE_TIME)) { + pr_err("Samples do not contain timestamps.\n"); + return -EINVAL; + } + + if (PRINT_FIELD(CPU) && + !(session->sample_type & PERF_SAMPLE_CPU)) { + pr_err("Samples do not contain cpu.\n"); + return -EINVAL; + } + + return 0; +} static void print_sample_start(struct perf_sample *sample, - struct thread *thread) + struct thread *thread, + struct perf_event_attr *attr) { int type; struct event *event; @@ -97,10 +148,13 @@ static void print_sample_start(struct perf_sample *sample, } if (PRINT_FIELD(EVNAME)) { - type = trace_parse_common_type(sample->raw_data); - event = trace_find_event(type); - if (event) - evname = event->name; + if (attr->type == PERF_TYPE_TRACEPOINT) { + type = trace_parse_common_type(sample->raw_data); + event = trace_find_event(type); + if (event) + evname = event->name; + } else + evname = __event_name(attr->type, attr->config); printf("%s: ", evname ? evname : "(unknown)"); } @@ -108,10 +162,27 @@ static void print_sample_start(struct perf_sample *sample, static void process_event(union perf_event *event __unused, struct perf_sample *sample, - struct perf_session *session __unused, + struct perf_session *session, struct thread *thread) { - print_sample_start(sample, thread); + struct perf_event_attr *attr; + struct perf_evsel *evsel; + + evsel = perf_evlist__id2evsel(session->evlist, sample->id); + if (evsel == NULL) { + pr_err("Invalid data. Contains samples with id not in " + "its header!\n"); + return; + } + attr = &evsel->attr; + + if (output_fields[attr->type] == 0) + return; + + if (perf_session__check_attr(session, attr) < 0) + return; + + print_sample_start(sample, thread, attr); if (PRINT_FIELD(TRACE)) print_trace_event(sample->cpu, sample->raw_data, @@ -183,19 +254,17 @@ static int process_sample_event(union perf_event *event, return -1; } - if (session->sample_type & PERF_SAMPLE_RAW) { - if (debug_mode) { - if (sample->time < last_timestamp) { - pr_err("Samples misordered, previous: %" PRIu64 - " this: %" PRIu64 "\n", last_timestamp, - sample->time); - nr_unordered++; - } - last_timestamp = sample->time; - return 0; + if (debug_mode) { + if (sample->time < last_timestamp) { + pr_err("Samples misordered, previous: %" PRIu64 + " this: %" PRIu64 "\n", last_timestamp, + sample->time); + nr_unordered++; } - scripting_ops->process_event(event, sample, session, thread); + last_timestamp = sample->time; + return 0; } + scripting_ops->process_event(event, sample, session, thread); session->hists.stats.total_period += sample->period; return 0; @@ -391,21 +460,40 @@ static int parse_output_fields(const struct option *opt __used, int i, imax = sizeof(all_output_options) / sizeof(struct output_option); int rc = 0; char *str = strdup(arg); + int type = -1; if (!str) return -ENOMEM; - tok = strtok(str, ","); + tok = strtok(str, ":"); if (!tok) { - fprintf(stderr, "Invalid field string."); + fprintf(stderr, + "Invalid field string - not prepended with type."); return -EINVAL; } - output_fields = 0; + /* first word should state which event type user + * is specifying the fields + */ + if (!strcmp(tok, "hw")) + type = PERF_TYPE_HARDWARE; + else if (!strcmp(tok, "sw")) + type = PERF_TYPE_SOFTWARE; + else if (!strcmp(tok, "trace")) + type = PERF_TYPE_TRACEPOINT; + else { + fprintf(stderr, "Invalid event type in field string."); + return -EINVAL; + } + + output_fields[type] = 0; while (1) { + tok = strtok(NULL, ","); + if (!tok) + break; for (i = 0; i < imax; ++i) { if (strcmp(tok, all_output_options[i].str) == 0) { - output_fields |= all_output_options[i].field; + output_fields[type] |= all_output_options[i].field; break; } } @@ -414,10 +502,11 @@ static int parse_output_fields(const struct option *opt __used, rc = -EINVAL; break; } + } - tok = strtok(NULL, ","); - if (!tok) - break; + if (output_fields[type] == 0) { + pr_debug("No fields requested for %s type. " + "Events will not be displayed\n", event_type(type)); } output_set_by_user = true; @@ -747,7 +836,7 @@ static const struct option options[] = { OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), OPT_CALLBACK('f', "fields", NULL, "str", - "comma separated output fields. Options: comm,tid,pid,time,cpu,event,trace,sym", + "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym", parse_output_fields), OPT_END() @@ -929,15 +1018,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (session == NULL) return -ENOMEM; - if (!no_callchain && (session->sample_type & PERF_SAMPLE_CALLCHAIN)) + if (!no_callchain) symbol_conf.use_callchain = true; else symbol_conf.use_callchain = false; - if (strcmp(input_name, "-") && - !perf_session__has_traces(session, "record -R")) - return -EINVAL; - if (generate_script_lang) { struct stat perf_stat; int input; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 54a7e2634d58..952b4ae3d954 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -263,6 +263,28 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result) return name; } +const char *event_type(int type) +{ + switch (type) { + case PERF_TYPE_HARDWARE: + return "hardware"; + + case PERF_TYPE_SOFTWARE: + return "software"; + + case PERF_TYPE_TRACEPOINT: + return "tracepoint"; + + case PERF_TYPE_HW_CACHE: + return "hardware-cache"; + + default: + break; + } + + return "unknown"; +} + const char *event_name(struct perf_evsel *evsel) { u64 config = evsel->attr.config; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 212f88e07a9c..746d3fcbfc2a 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -20,6 +20,7 @@ struct tracepoint_path { extern struct tracepoint_path *tracepoint_id_to_path(u64 config); extern bool have_tracepoints(struct list_head *evlist); +const char *event_type(int type); const char *event_name(struct perf_evsel *event); extern const char *__event_name(int type, u64 config); From 43adec955edd116c3e98c6e2f85fbd63281f5221 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 15 Mar 2011 11:04:13 -0300 Subject: [PATCH 12/12] perf evlist: New command to list the names of events present in a perf.data file [root@emilia ~]# perf record -a -e sched:* -e timer:timer* sleep 5 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.172 MB perf.data (~7530 samples) ] [root@emilia ~]# perf evlist sched:sched_kthread_stop sched:sched_kthread_stop_ret sched:sched_wakeup sched:sched_wakeup_new sched:sched_switch sched:sched_migrate_task sched:sched_process_free sched:sched_process_exit sched:sched_wait_task sched:sched_process_wait sched:sched_process_fork sched:sched_stat_wait sched:sched_stat_sleep sched:sched_stat_iowait sched:sched_stat_runtime sched:sched_pi_setprio timer:timer_init timer:timer_start timer:timer_expire_entry timer:timer_expire_exit timer:timer_cancel [root@emilia ~]# 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-evlist.txt | 26 ++++++++++++ tools/perf/Makefile | 1 + tools/perf/builtin-evlist.c | 54 ++++++++++++++++++++++++ tools/perf/builtin.h | 1 + tools/perf/command-list.txt | 1 + tools/perf/perf.c | 1 + 6 files changed, 84 insertions(+) create mode 100644 tools/perf/Documentation/perf-evlist.txt create mode 100644 tools/perf/builtin-evlist.c diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt new file mode 100644 index 000000000000..0cada9e053dc --- /dev/null +++ b/tools/perf/Documentation/perf-evlist.txt @@ -0,0 +1,26 @@ +perf-evlist(1) +============== + +NAME +---- +perf-evlist - List the event names in a perf.data file + +SYNOPSIS +-------- +[verse] +'perf evlist ' + +DESCRIPTION +----------- +This command displays the names of events sampled in a perf.data file. + +OPTIONS +------- +-i:: +--input=:: + Input file name. (default: perf.data) + +SEE ALSO +-------- +linkperf:perf-record[1], linkperf:perf-list[1], +linkperf:perf-report[1] diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 9b8421805c5c..158c30e8210c 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -338,6 +338,7 @@ endif BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o BUILTIN_OBJS += $(OUTPUT)builtin-diff.o +BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o BUILTIN_OBJS += $(OUTPUT)builtin-help.o BUILTIN_OBJS += $(OUTPUT)builtin-sched.o BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c new file mode 100644 index 000000000000..4c5e9e04a41f --- /dev/null +++ b/tools/perf/builtin-evlist.c @@ -0,0 +1,54 @@ +/* + * Builtin evlist command: Show the list of event selectors present + * in a perf.data file. + */ +#include "builtin.h" + +#include "util/util.h" + +#include + +#include "perf.h" +#include "util/evlist.h" +#include "util/evsel.h" +#include "util/parse-events.h" +#include "util/parse-options.h" +#include "util/session.h" + +static char const *input_name = "perf.data"; + +static int __cmd_evlist(void) +{ + struct perf_session *session; + struct perf_evsel *pos; + + session = perf_session__new(input_name, O_RDONLY, 0, false, NULL); + if (session == NULL) + return -ENOMEM; + + list_for_each_entry(pos, &session->evlist->entries, node) + printf("%s\n", event_name(pos)); + + perf_session__delete(session); + return 0; +} + +static const char * const evlist_usage[] = { + "perf evlist []", + 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) +{ + argc = parse_options(argc, argv, options, evlist_usage, 0); + if (argc) + usage_with_options(evlist_usage, options); + + return __cmd_evlist(); +} diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index c7798c7f24ed..4702e2443a8e 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -19,6 +19,7 @@ extern int cmd_bench(int argc, const char **argv, const char *prefix); extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix); extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); extern int cmd_diff(int argc, const char **argv, const char *prefix); +extern int cmd_evlist(int argc, const char **argv, const char *prefix); extern int cmd_help(int argc, const char **argv, const char *prefix); extern int cmd_sched(int argc, const char **argv, const char *prefix); extern int cmd_list(int argc, const char **argv, const char *prefix); diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 16b5088cf8f4..d695fe40fbff 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt @@ -8,6 +8,7 @@ perf-bench mainporcelain common perf-buildid-cache mainporcelain common perf-buildid-list mainporcelain common perf-diff mainporcelain common +perf-evlist mainporcelain common perf-inject mainporcelain common perf-list mainporcelain common perf-sched mainporcelain common diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 595d0f4a7103..ec635b7cc8ea 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -313,6 +313,7 @@ static void handle_internal_command(int argc, const char **argv) { "buildid-cache", cmd_buildid_cache, 0 }, { "buildid-list", cmd_buildid_list, 0 }, { "diff", cmd_diff, 0 }, + { "evlist", cmd_evlist, 0 }, { "help", cmd_help, 0 }, { "list", cmd_list, 0 }, { "record", cmd_record, 0 },