From 7be5ebe8767eaa482e18f566de5f56c1519abf59 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 14:53:43 -0300 Subject: perf evsel: Update sample_size when setting sample_type bits We use evsel->sample_size to detect underflows in perf_evsel__parse_sample, but we were failing to update it after perf_evsel__init(), i.e. when we decide, after creating an evsel, that we want some extra field bit set. Fix it by introducing methods to set a bit that will take care of correctly adjusting evsel->sample_size. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2ny5pzsing0dcth7hws48x9c@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f3151d3c70ce..0be6605db9ea 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -286,7 +286,7 @@ try_again: */ opts->sample_id_all_missing = true; if (!opts->sample_time && !opts->raw_samples && !time_needed) - attr->sample_type &= ~PERF_SAMPLE_TIME; + perf_evsel__reset_sample_bit(pos, TIME); goto retry_sample_id; } -- cgit v1.2.3 From f77a951826b44b763e4d9fbd2479b6132d2bd7fc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Dec 2012 16:41:31 -0300 Subject: perf evlist: Set the leader in the perf_evlist__config method Since we need to ensure the leader is set before configuring the evsel perf_event_attrs. Reducing the boilerplate needed by tools, helping, for instance, 'perf trace', that wasn't setting the leader. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-22shm0ptkch2kgl7rtqlligx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 9 +-------- tools/perf/builtin-trace.c | 2 +- tools/perf/tests/perf-record.c | 2 +- tools/perf/util/evlist.c | 10 ++++++++-- tools/perf/util/evlist.h | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 0be6605db9ea..fc4f08044632 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -230,14 +230,7 @@ static int perf_record__open(struct perf_record *rec) struct perf_record_opts *opts = &rec->opts; int rc = 0; - /* - * Set the evsel leader links before we configure attributes, - * since some might depend on this info. - */ - if (opts->group) - perf_evlist__set_leader(evlist); - - perf_evlist__config_attrs(evlist, opts); + perf_evlist__config(evlist, opts); list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 7932ffa29889..d222d7fc7e96 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -455,7 +455,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) goto out_delete_evlist; } - perf_evlist__config_attrs(evlist, &trace->opts); + perf_evlist__config(evlist, &trace->opts); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 5902772492b6..6ea66cf6791b 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c @@ -106,7 +106,7 @@ int test__PERF_RECORD(void) perf_evsel__set_sample_bit(evsel, CPU); perf_evsel__set_sample_bit(evsel, TID); perf_evsel__set_sample_bit(evsel, TIME); - perf_evlist__config_attrs(evlist, &opts); + perf_evlist__config(evlist, &opts); err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); if (err < 0) { diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 5a0878d3a038..dc8aee97a488 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -49,10 +49,16 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, return evlist; } -void perf_evlist__config_attrs(struct perf_evlist *evlist, - struct perf_record_opts *opts) +void perf_evlist__config(struct perf_evlist *evlist, + struct perf_record_opts *opts) { struct perf_evsel *evsel; + /* + * Set the evsel leader links before we configure attributes, + * since some might depend on this info. + */ + if (opts->group) + perf_evlist__set_leader(evlist); if (evlist->cpus->map[0] < 0) opts->no_inherit = true; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 56003f779e60..457e2350d21d 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -76,8 +76,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); int perf_evlist__open(struct perf_evlist *evlist); -void perf_evlist__config_attrs(struct perf_evlist *evlist, - struct perf_record_opts *opts); +void perf_evlist__config(struct perf_evlist *evlist, + struct perf_record_opts *opts); int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct perf_record_opts *opts, -- cgit v1.2.3 From c5ff78c3092d0e7d14c82d2949e16fee063a83f1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Dec 2012 16:16:47 -0300 Subject: perf record: Pass perf_record_opts to the callchain cmdline parsing callback Its all it uses and makes the parsing callback suitable for use by 'perf top', which will happen in a followup patch. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-wb9eti78bk2jd7wpasro8hsz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index fc4f08044632..d035040efe1d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -868,11 +868,9 @@ static int get_stack_size(char *str, unsigned long *_size) } #endif /* LIBUNWIND_SUPPORT */ -static int -parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, - int unset) +static int parse_callchain_opt(const struct option *opt, const char *arg, int unset) { - struct perf_record *rec = (struct perf_record *)opt->value; + struct perf_record_opts *opts = opt->value; char *tok, *name, *saveptr = NULL; char *buf; int ret = -1; @@ -898,7 +896,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, /* Framepointer style */ if (!strncmp(name, "fp", sizeof("fp"))) { if (!strtok_r(NULL, ",", &saveptr)) { - rec->opts.call_graph = CALLCHAIN_FP; + opts->call_graph = CALLCHAIN_FP; ret = 0; } else pr_err("callchain: No more arguments " @@ -911,20 +909,20 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, const unsigned long default_stack_dump_size = 8192; ret = 0; - rec->opts.call_graph = CALLCHAIN_DWARF; - rec->opts.stack_dump_size = default_stack_dump_size; + opts->call_graph = CALLCHAIN_DWARF; + opts->stack_dump_size = default_stack_dump_size; tok = strtok_r(NULL, ",", &saveptr); if (tok) { unsigned long size = 0; ret = get_stack_size(tok, &size); - rec->opts.stack_dump_size = size; + opts->stack_dump_size = size; } if (!ret) pr_debug("callchain: stack dump size %d\n", - rec->opts.stack_dump_size); + opts->stack_dump_size); #endif /* LIBUNWIND_SUPPORT */ } else { pr_err("callchain: Unknown -g option " @@ -937,7 +935,7 @@ parse_callchain_opt(const struct option *opt __maybe_unused, const char *arg, free(buf); if (!ret) - pr_debug("callchain: type %d\n", rec->opts.call_graph); + pr_debug("callchain: type %d\n", opts->call_graph); return ret; } @@ -1021,9 +1019,9 @@ const struct option record_options[] = { "number of mmap data pages"), OPT_BOOLEAN(0, "group", &record.opts.group, "put the counters into a counter group"), - OPT_CALLBACK_DEFAULT('g', "call-graph", &record, "mode[,dump_size]", - callchain_help, &parse_callchain_opt, - "fp"), + OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, + "mode[,dump_size]", callchain_help, + &parse_callchain_opt, "fp"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), -- cgit v1.2.3 From 75d9a10854db6aab2400cd6a844c392107be4c64 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Dec 2012 16:46:05 -0300 Subject: perf record: Export the callchain parsing routine and help Will be used by perf top, that will first setup the symbol system to deal with callchains and then call these routines to ask the kernel for callchains. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jg0dh8rmlx7x11e7u7mnasvd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 11 ++++++----- tools/perf/util/callchain.h | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d035040efe1d..028de726b832 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -868,7 +868,8 @@ static int get_stack_size(char *str, unsigned long *_size) } #endif /* LIBUNWIND_SUPPORT */ -static int parse_callchain_opt(const struct option *opt, const char *arg, int unset) +int record_parse_callchain_opt(const struct option *opt, + const char *arg, int unset) { struct perf_record_opts *opts = opt->value; char *tok, *name, *saveptr = NULL; @@ -973,9 +974,9 @@ static struct perf_record record = { #define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: " #ifdef LIBUNWIND_SUPPORT -static const char callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; +const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf"; #else -static const char callchain_help[] = CALLCHAIN_HELP "[fp]"; +const char record_callchain_help[] = CALLCHAIN_HELP "[fp]"; #endif /* @@ -1020,8 +1021,8 @@ const struct option record_options[] = { OPT_BOOLEAN(0, "group", &record.opts.group, "put the counters into a counter group"), OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts, - "mode[,dump_size]", callchain_help, - &parse_callchain_opt, "fp"), + "mode[,dump_size]", record_callchain_help, + &record_parse_callchain_opt, "fp"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index eb340571e7d6..3ee9f67d5af0 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -143,4 +143,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) cursor->curr = cursor->curr->next; cursor->pos++; } + +struct option; + +int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); +extern const char record_callchain_help[]; #endif /* __PERF_CALLCHAIN_H */ -- cgit v1.2.3 From 594ac61ad3be9c80c738a9fe3bb95c05d8d1bae1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Dec 2012 13:13:07 -0300 Subject: perf evsel: Do missing feature fallbacks in just one place Instead of doing it in stat, top, record or any other tool that opens event descriptors. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-vr8hzph83d5t2mdlkf565h84@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 36 ------------------------------------ tools/perf/builtin-stat.c | 30 +++--------------------------- tools/perf/builtin-top.c | 20 -------------------- tools/perf/perf.h | 2 -- tools/perf/util/evsel.c | 31 ++++++++++++++++++++++++++++--- tools/perf/util/top.h | 2 -- 6 files changed, 31 insertions(+), 90 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 028de726b832..a4b97269cfc6 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -234,25 +234,6 @@ static int perf_record__open(struct perf_record *rec) list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; - /* - * Check if parse_single_tracepoint_event has already asked for - * PERF_SAMPLE_TIME. - * - * XXX this is kludgy but short term fix for problems introduced by - * eac23d1c that broke 'perf script' by having different sample_types - * when using multiple tracepoint events when we use a perf binary - * that tries to use sample_id_all on an older kernel. - * - * We need to move counter creation to perf_session, support - * different sample_types, etc. - */ - bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - -fallback_missing_features: - if (opts->exclude_guest_missing) - attr->exclude_guest = attr->exclude_host = 0; -retry_sample_id: - attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; try_again: if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { int err = errno; @@ -266,23 +247,6 @@ try_again: " an out-of-range profile CPU?\n"); rc = -err; goto out; - } else if (err == EINVAL) { - if (!opts->exclude_guest_missing && - (attr->exclude_guest || attr->exclude_host)) { - pr_debug("Old kernel, cannot exclude " - "guest or host samples.\n"); - opts->exclude_guest_missing = true; - goto fallback_missing_features; - } else if (!opts->sample_id_all_missing) { - /* - * Old kernel, no attr->sample_id_type_all field - */ - opts->sample_id_all_missing = true; - if (!opts->sample_time && !opts->raw_samples && !time_needed) - perf_evsel__reset_sample_bit(pos, TIME); - - goto retry_sample_id; - } } /* diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c12655af2b88..ef067c193f93 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -132,8 +132,6 @@ static struct stats walltime_nsecs_stats; static int create_perf_stat_counter(struct perf_evsel *evsel) { struct perf_event_attr *attr = &evsel->attr; - bool exclude_guest_missing = false; - int ret; if (scale) attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | @@ -141,16 +139,8 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) attr->inherit = !no_inherit; -retry: - if (exclude_guest_missing) - evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; - - if (perf_target__has_cpu(&target)) { - ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); - if (ret) - goto check_ret; - return 0; - } + if (perf_target__has_cpu(&target)) + return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); if (!perf_target__has_task(&target) && perf_evsel__is_group_leader(evsel)) { @@ -158,21 +148,7 @@ retry: attr->enable_on_exec = 1; } - ret = perf_evsel__open_per_thread(evsel, evsel_list->threads); - if (!ret) - return 0; - /* fall through */ -check_ret: - if (ret && errno == EINVAL) { - if (!exclude_guest_missing && - (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { - pr_debug("Old kernel, cannot exclude " - "guest or host samples.\n"); - exclude_guest_missing = true; - goto retry; - } - } - return ret; + return perf_evsel__open_per_thread(evsel, evsel_list->threads); } /* diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b7d2ea62dbc6..74fca619fc4e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -900,12 +900,6 @@ static void perf_top__start_counters(struct perf_top *top) list_for_each_entry(counter, &evlist->entries, node) { struct perf_event_attr *attr = &counter->attr; - -fallback_missing_features: - if (top->exclude_guest_missing) - attr->exclude_guest = attr->exclude_host = 0; -retry_sample_id: - attr->sample_id_all = top->sample_id_all_missing ? 0 : 1; try_again: if (perf_evsel__open(counter, top->evlist->cpus, top->evlist->threads) < 0) { @@ -914,20 +908,6 @@ try_again: if (err == EPERM || err == EACCES) { ui__error_paranoid(); goto out_err; - } else if (err == EINVAL) { - if (!top->exclude_guest_missing && - (attr->exclude_guest || attr->exclude_host)) { - pr_debug("Old kernel, cannot exclude " - "guest or host samples.\n"); - top->exclude_guest_missing = true; - goto fallback_missing_features; - } else if (!top->sample_id_all_missing) { - /* - * Old kernel, no attr->sample_id_type_all field - */ - top->sample_id_all_missing = true; - goto retry_sample_id; - } } /* * If it's cycles then fall back to hrtimer diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 2c340e7da458..7622f15bcfb7 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -237,8 +237,6 @@ struct perf_record_opts { bool raw_samples; bool sample_address; bool sample_time; - bool sample_id_all_missing; - bool exclude_guest_missing; bool period; unsigned int freq; unsigned int mmap_pages; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 7a2a3dc3ff03..ee6ee3f45c2a 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -22,6 +22,11 @@ #include #include "perf_regs.h" +static struct { + bool sample_id_all; + bool exclude_guest; +} perf_missing_features; + #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) static int __perf_evsel__sample_size(u64 sample_type) @@ -463,7 +468,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_event_attr *attr = &evsel->attr; int track = !evsel->idx; /* only the first counter needs these */ - attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; + attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; attr->inherit = !opts->no_inherit; perf_evsel__set_sample_bit(evsel, IP); @@ -513,7 +518,7 @@ void perf_evsel__config(struct perf_evsel *evsel, if (opts->period) perf_evsel__set_sample_bit(evsel, PERIOD); - if (!opts->sample_id_all_missing && + if (!perf_missing_features.sample_id_all && (opts->sample_time || !opts->no_inherit || perf_target__has_cpu(&opts->target))) perf_evsel__set_sample_bit(evsel, TIME); @@ -761,6 +766,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, pid = evsel->cgrp->fd; } +fallback_missing_features: + if (perf_missing_features.exclude_guest) + evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; +retry_sample_id: + if (perf_missing_features.sample_id_all) + evsel->attr.sample_id_all = 0; + for (cpu = 0; cpu < cpus->nr; cpu++) { for (thread = 0; thread < threads->nr; thread++) { @@ -777,13 +789,26 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, group_fd, flags); if (FD(evsel, cpu, thread) < 0) { err = -errno; - goto out_close; + goto try_fallback; } } } return 0; +try_fallback: + if (err != -EINVAL || cpu > 0 || thread > 0) + goto out_close; + + if (!perf_missing_features.exclude_guest && + (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { + perf_missing_features.exclude_guest = true; + goto fallback_missing_features; + } else if (!perf_missing_features.sample_id_all) { + perf_missing_features.sample_id_all = true; + goto retry_sample_id; + } + out_close: do { while (--thread >= 0) { diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 927c229c2d9a..7ebf357dc9e1 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -29,8 +29,6 @@ struct perf_top { bool sort_has_symbols; bool kptr_restrict_warned; bool vmlinux_warned; - bool sample_id_all_missing; - bool exclude_guest_missing; bool dump_symtab; struct hist_entry *sym_filter_entry; struct perf_evsel *sym_evsel; -- cgit v1.2.3 From c0a54341c0e89333ef201fc3f3001176962f6121 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Dec 2012 14:16:30 -0300 Subject: perf evsel: Introduce event fallback method The only fallback right now is for HW cpu-cycles -> SW cpu-clock, that was done in the same way in both 'top' and 'record'. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-58l1mgibh9oa9m0pd3fasxa5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 23 +++-------------------- tools/perf/builtin-top.c | 20 +++----------------- tools/perf/util/evsel.c | 28 ++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 3 +++ 4 files changed, 37 insertions(+), 37 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a4b97269cfc6..b8d0a39b484e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -224,6 +224,7 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, static int perf_record__open(struct perf_record *rec) { + char msg[128]; struct perf_evsel *pos; struct perf_evlist *evlist = rec->evlist; struct perf_session *session = rec->session; @@ -249,27 +250,9 @@ try_again: goto out; } - /* - * If it's cycles then fall back to hrtimer - * based cpu-clock-tick sw counter, which - * is always available even if no PMU support. - * - * PPC returns ENXIO until 2.6.37 (behavior changed - * with commit b0a873e). - */ - if ((err == ENOENT || err == ENXIO) - && attr->type == PERF_TYPE_HARDWARE - && attr->config == PERF_COUNT_HW_CPU_CYCLES) { - + if (perf_evsel__fallback(pos, err, msg, sizeof(msg))) { if (verbose) - ui__warning("The cycles event is not supported, " - "trying to fall back to cpu-clock-ticks\n"); - attr->type = PERF_TYPE_SOFTWARE; - attr->config = PERF_COUNT_SW_CPU_CLOCK; - if (pos->name) { - free(pos->name); - pos->name = NULL; - } + ui__warning("%s\n", msg); goto try_again; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 74fca619fc4e..8d41d0b58956 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -892,6 +892,7 @@ static void perf_top__mmap_read(struct perf_top *top) static void perf_top__start_counters(struct perf_top *top) { + char msg[128]; struct perf_evsel *counter; struct perf_evlist *evlist = top->evlist; struct perf_record_opts *opts = &top->record_opts; @@ -909,25 +910,10 @@ try_again: ui__error_paranoid(); goto out_err; } - /* - * If it's cycles then fall back to hrtimer - * based cpu-clock-tick sw counter, which - * is always available even if no PMU support: - */ - if ((err == ENOENT || err == ENXIO) && - (attr->type == PERF_TYPE_HARDWARE) && - (attr->config == PERF_COUNT_HW_CPU_CYCLES)) { + if (perf_evsel__fallback(counter, err, msg, sizeof(msg))) { if (verbose) - ui__warning("Cycles event not supported,\n" - "trying to fall back to cpu-clock-ticks\n"); - - attr->type = PERF_TYPE_SOFTWARE; - attr->config = PERF_COUNT_SW_CPU_CLOCK; - if (counter->name) { - free(counter->name); - counter->name = NULL; - } + ui__warning("%s\n", msg); goto try_again; } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ee6ee3f45c2a..0c88e5c12dab 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1378,3 +1378,31 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, fputc('\n', fp); return ++printed; } + +bool perf_evsel__fallback(struct perf_evsel *evsel, int err, + char *msg, size_t msgsize) +{ + if ((err == ENOENT || err == ENXIO) && + evsel->attr.type == PERF_TYPE_HARDWARE && + evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { + /* + * If it's cycles then fall back to hrtimer based + * cpu-clock-tick sw counter, which is always available even if + * no PMU support. + * + * PPC returns ENXIO until 2.6.37 (behavior changed with commit + * b0a873e). + */ + scnprintf(msg, msgsize, "%s", +"The cycles event is not supported, trying to fall back to cpu-clock-ticks"); + + evsel->attr.type = PERF_TYPE_SOFTWARE; + evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; + + free(evsel->name); + evsel->name = NULL; + return true; + } + + return false; +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 9cb8a0215711..26d8cfd86e0a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -251,4 +251,7 @@ struct perf_attr_details { int perf_evsel__fprintf(struct perf_evsel *evsel, struct perf_attr_details *details, FILE *fp); + +bool perf_evsel__fallback(struct perf_evsel *evsel, int err, + char *msg, size_t msgsize); #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3 From 56e52e85366717481cde16b3480f015c7eb32ba3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 13 Dec 2012 15:10:58 -0300 Subject: perf evsel: Introduce perf_evsel__open_strerror method That consolidates the error messages in 'record', 'stat' and 'top', that now get a consistent set of messages and allow other tools to use the new method to report problems using whatever UI toolkit. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1cudb7wl996kz7ilz83ctvhr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 54 +++++---------------------------------------- tools/perf/builtin-stat.c | 16 +++++--------- tools/perf/builtin-top.c | 34 +++++----------------------- tools/perf/ui/util.c | 11 --------- tools/perf/util/debug.h | 1 - tools/perf/util/evsel.c | 49 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.h | 3 +++ 7 files changed, 68 insertions(+), 100 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b8d0a39b484e..de60dd4ee5d3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -224,7 +224,7 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, static int perf_record__open(struct perf_record *rec) { - char msg[128]; + char msg[512]; struct perf_evsel *pos; struct perf_evlist *evlist = rec->evlist; struct perf_session *session = rec->session; @@ -234,60 +234,18 @@ static int perf_record__open(struct perf_record *rec) perf_evlist__config(evlist, opts); list_for_each_entry(pos, &evlist->entries, node) { - struct perf_event_attr *attr = &pos->attr; try_again: if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { - int err = errno; - - if (err == EPERM || err == EACCES) { - ui__error_paranoid(); - rc = -err; - goto out; - } else if (err == ENODEV && opts->target.cpu_list) { - pr_err("No such device - did you specify" - " an out-of-range profile CPU?\n"); - rc = -err; - goto out; - } - - if (perf_evsel__fallback(pos, err, msg, sizeof(msg))) { + if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { if (verbose) ui__warning("%s\n", msg); goto try_again; } - if (err == ENOENT) { - ui__error("The %s event is not supported.\n", - perf_evsel__name(pos)); - rc = -err; - goto out; - } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { - ui__error("\'precise\' request may not be supported. " - "Try removing 'p' modifier\n"); - rc = -err; - goto out; - } - - printf("\n"); - error("sys_perf_event_open() syscall returned with %d " - "(%s) for event %s. /bin/dmesg may provide " - "additional information.\n", - err, strerror(err), perf_evsel__name(pos)); - -#if defined(__i386__) || defined(__x86_64__) - if (attr->type == PERF_TYPE_HARDWARE && - err == EOPNOTSUPP) { - pr_err("No hardware sampling interrupt available." - " No APIC? If so then you can boot the kernel" - " with the \"lapic\" boot parameter to" - " force-enable it.\n"); - rc = -err; - goto out; - } -#endif - - pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); - rc = -err; + rc = -errno; + perf_evsel__open_strerror(pos, &opts->target, + errno, msg, sizeof(msg)); + ui__error("%s\n", msg); goto out; } } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ef067c193f93..1c2ac148a7d5 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -247,6 +247,7 @@ static int read_counter(struct perf_evsel *counter) static int __run_perf_stat(int argc __maybe_unused, const char **argv) { + char msg[512]; unsigned long long t0, t1; struct perf_evsel *counter; int status = 0; @@ -324,20 +325,13 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) continue; } - if (errno == EPERM || errno == EACCES) { - error("You may not have permission to collect %sstats.\n" - "\t Consider tweaking" - " /proc/sys/kernel/perf_event_paranoid or running as root.", - target.system_wide ? "system-wide " : ""); - } else { - error("open_counter returned with %d (%s). " - "/bin/dmesg may provide additional information.\n", - errno, strerror(errno)); - } + perf_evsel__open_strerror(counter, &target, + errno, msg, sizeof(msg)); + ui__error("%s\n", msg); + if (child_pid != -1) kill(child_pid, SIGTERM); - pr_err("Not all events could be opened.\n"); return -1; } counter->supported = true; diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8d41d0b58956..f5fd260f7b20 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -892,7 +892,7 @@ static void perf_top__mmap_read(struct perf_top *top) static void perf_top__start_counters(struct perf_top *top) { - char msg[128]; + char msg[512]; struct perf_evsel *counter; struct perf_evlist *evlist = top->evlist; struct perf_record_opts *opts = &top->record_opts; @@ -900,42 +900,18 @@ static void perf_top__start_counters(struct perf_top *top) perf_evlist__config(evlist, opts); list_for_each_entry(counter, &evlist->entries, node) { - struct perf_event_attr *attr = &counter->attr; try_again: if (perf_evsel__open(counter, top->evlist->cpus, top->evlist->threads) < 0) { - int err = errno; - - if (err == EPERM || err == EACCES) { - ui__error_paranoid(); - goto out_err; - } - - if (perf_evsel__fallback(counter, err, msg, sizeof(msg))) { + if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { if (verbose) ui__warning("%s\n", msg); goto try_again; } - if (err == ENOENT) { - ui__error("The %s event is not supported.\n", - perf_evsel__name(counter)); - goto out_err; - } else if (err == EMFILE) { - ui__error("Too many events are opened.\n" - "Try again after reducing the number of events\n"); - goto out_err; - } else if ((err == EOPNOTSUPP) && (attr->precise_ip)) { - ui__error("\'precise\' request may not be supported. " - "Try removing 'p' modifier\n"); - goto out_err; - } - - ui__error("The sys_perf_event_open() syscall " - "returned with %d (%s). /bin/dmesg " - "may provide additional information.\n" - "No CONFIG_PERF_EVENTS=y kernel support " - "configured?\n", err, strerror(err)); + perf_evsel__open_strerror(counter, &opts->target, + errno, msg, sizeof(msg)); + ui__error("%s\n", msg); goto out_err; } } diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 3014a7cd5271..e3e0a963d03a 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c @@ -52,17 +52,6 @@ int ui__warning(const char *format, ...) return ret; } -int ui__error_paranoid(void) -{ - return ui__error("Permission error - are you root?\n" - "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" - " -1 - Not paranoid at all\n" - " 0 - Disallow raw tracepoint access for unpriv\n" - " 1 - Disallow cpu events for unpriv\n" - " 2 - Disallow kernel profiling for unpriv\n"); -} - - /** * perf_error__register - Register error logging functions * @eops: The pointer to error logging function struct diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 6e2667fb8211..efbd98805ad0 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -16,6 +16,5 @@ void trace_event(union perf_event *event); int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); -int ui__error_paranoid(void); #endif /* __PERF_DEBUG_H */ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0c88e5c12dab..e45332d08a58 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1406,3 +1406,52 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, return false; } + +int perf_evsel__open_strerror(struct perf_evsel *evsel, + struct perf_target *target, + int err, char *msg, size_t size) +{ + switch (err) { + case EPERM: + case EACCES: + return scnprintf(msg, size, "%s", + "You may not have permission to collect %sstats.\n" + "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" + " -1 - Not paranoid at all\n" + " 0 - Disallow raw tracepoint access for unpriv\n" + " 1 - Disallow cpu events for unpriv\n" + " 2 - Disallow kernel profiling for unpriv", + target->system_wide ? "system-wide " : ""); + case ENOENT: + return scnprintf(msg, size, "The %s event is not supported.", + perf_evsel__name(evsel)); + case EMFILE: + return scnprintf(msg, size, "%s", + "Too many events are opened.\n" + "Try again after reducing the number of events."); + case ENODEV: + if (target->cpu_list) + return scnprintf(msg, size, "%s", + "No such device - did you specify an out-of-range profile CPU?\n"); + break; + case EOPNOTSUPP: + if (evsel->attr.precise_ip) + return scnprintf(msg, size, "%s", + "\'precise\' request may not be supported. Try removing 'p' modifier."); +#if defined(__i386__) || defined(__x86_64__) + if (evsel->attr.type == PERF_TYPE_HARDWARE) + return scnprintf(msg, size, "%s", + "No hardware sampling interrupt available.\n" + "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); +#endif + break; + default: + break; + } + + return scnprintf(msg, size, + "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n" + "/bin/dmesg may provide additional information.\n" + "No CONFIG_PERF_EVENTS=y kernel support configured?\n", + err, strerror(err), perf_evsel__name(evsel)); +} diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 26d8cfd86e0a..c68d1b82e843 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -254,4 +254,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, bool perf_evsel__fallback(struct perf_evsel *evsel, int err, char *msg, size_t msgsize); +int perf_evsel__open_strerror(struct perf_evsel *evsel, + struct perf_target *target, + int err, char *msg, size_t size); #endif /* __PERF_EVSEL_H */ -- cgit v1.2.3 From 7e383de42565ecb2cf641fff11946f9bc45e8235 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Dec 2012 15:49:27 -0300 Subject: perf record: Don't pass host machine to guest synthesizer We were calling perf_session__process_machines(), that would first pass the struct machine associated with the host to the provided callback, perf_event__synthesize_guest_os() that would test if it was the host and if so wouldn't do anything. Ditch this contraption, just call directly machines__process with the list of guests. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-x65vsxgzg4dvo3zqohtrrb9o@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 11 ++++------- tools/perf/util/session.h | 9 --------- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index de60dd4ee5d3..69e28950a328 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -328,10 +328,6 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; struct perf_tool *tool = data; - - if (machine__is_host(machine)) - return; - /* *As for guest kernel when processing subcommand record&report, *we arrange module mmap prior to guest kernel mmap and trigger @@ -574,9 +570,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/modules permission or run as root.\n"); - if (perf_guest) - perf_session__process_machines(session, tool, - perf_event__synthesize_guest_os); + if (perf_guest) { + machines__process(&session->machines, + perf_event__synthesize_guest_os, tool); + } if (!opts->target.system_wide) err = perf_event__synthesize_thread_map(tool, evsel_list->threads, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 8c2302504199..426ca0c3c5b6 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -101,15 +101,6 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p return machines__findnew(&self->machines, pid); } -static inline -void perf_session__process_machines(struct perf_session *self, - struct perf_tool *tool, - machine__process_t process) -{ - process(&self->host_machine, tool); - return machines__process(&self->machines, process, tool); -} - struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); size_t perf_session__fprintf(struct perf_session *self, FILE *fp); -- cgit v1.2.3 From 876650e6c3209861a8949111140d805b3440951f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Dec 2012 19:15:48 -0300 Subject: perf machine: Introduce struct machines That consolidates the grouping of host + guests, isolating a bit more of functionality now centered on 'perf_session' that can be used independently in tools that don't need a 'perf_session' instance, but needs to have all the thread/map/symbol machinery. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-c700rsiphpmzv8klogojpfut@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 +-- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-top.c | 4 +-- tools/perf/tests/hists_link.c | 17 +++++------- tools/perf/util/header.c | 12 ++++---- tools/perf/util/machine.c | 64 ++++++++++++++++++++++++++++--------------- tools/perf/util/machine.h | 32 ++++++++++++++-------- tools/perf/util/session.c | 30 ++++++++------------ tools/perf/util/session.h | 11 ++------ 9 files changed, 95 insertions(+), 81 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 69e28950a328..a0b2427b509d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -571,8 +571,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) "Check /proc/modules permission or run as root.\n"); if (perf_guest) { - machines__process(&session->machines, - perf_event__synthesize_guest_os, tool); + machines__process_guests(&session->machines, + perf_event__synthesize_guest_os, tool); } if (!opts->target.system_wide) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 5134acf1c39a..13cdf61c4f82 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -372,7 +372,7 @@ static int __cmd_report(struct perf_report *rep) if (ret) goto out_delete; - kernel_map = session->host_machine.vmlinux_maps[MAP__FUNCTION]; + kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; kernel_kmap = map__kmap(kernel_map); if (kernel_map == NULL || (kernel_map->dso->hit && diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 996b10c702ba..e0ecebdde3fe 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -966,10 +966,10 @@ static int __cmd_top(struct perf_top *top) if (perf_target__has_task(&opts->target)) perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, perf_event__process, - &top->session->host_machine); + &top->session->machines.host); else perf_event__synthesize_threads(&top->tool, perf_event__process, - &top->session->host_machine); + &top->session->machines.host); perf_top__start_counters(top); top->session->evlist = top->evlist; perf_session__set_id_hdr_size(top->session); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 0f1aae3b8a99..27860a082381 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -75,13 +75,11 @@ static struct { { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) }, }; -static struct machine *setup_fake_machine(void) +static struct machine *setup_fake_machine(struct machines *machines) { - struct rb_root machine_root = RB_ROOT; - struct machine *machine; + struct machine *machine = machines__find(machines, HOST_KERNEL_ID); size_t i; - machine = machines__findnew(&machine_root, HOST_KERNEL_ID); if (machine == NULL) { pr_debug("Not enough memory for machine setup\n"); return NULL; @@ -435,6 +433,7 @@ static void print_hists(struct hists *hists) int test__hists_link(void) { int err = -1; + struct machines machines; struct machine *machine = NULL; struct perf_evsel *evsel, *first; struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); @@ -452,8 +451,10 @@ int test__hists_link(void) /* default sort order (comm,dso,sym) will be used */ setup_sorting(NULL, NULL); + machines__init(&machines); + /* setup threads/dso/map/symbols also */ - machine = setup_fake_machine(); + machine = setup_fake_machine(&machines); if (!machine) goto out; @@ -492,11 +493,7 @@ int test__hists_link(void) out: /* tear down everything */ perf_evlist__delete(evlist); - - if (machine) { - machine__delete_threads(machine); - machine__delete(machine); - } + machines__exit(&machines); return err; } diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index bb578d2d10f9..fccd69dbbbb9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -287,12 +287,12 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd) struct perf_session *session = container_of(header, struct perf_session, header); struct rb_node *nd; - int err = machine__write_buildid_table(&session->host_machine, fd); + int err = machine__write_buildid_table(&session->machines.host, fd); if (err) return err; - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); err = machine__write_buildid_table(pos, fd); if (err) @@ -448,9 +448,9 @@ static int perf_session__cache_build_ids(struct perf_session *session) if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) return -1; - ret = machine__cache_build_ids(&session->host_machine, debugdir); + ret = machine__cache_build_ids(&session->machines.host, debugdir); - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__cache_build_ids(pos, debugdir); } @@ -467,9 +467,9 @@ static bool machine__read_build_ids(struct machine *machine, bool with_hits) static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) { struct rb_node *nd; - bool ret = machine__read_build_ids(&session->host_machine, with_hits); + bool ret = machine__read_build_ids(&session->machines.host, with_hits); - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret |= machine__read_build_ids(pos, with_hits); } diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 71fa90391fe4..efdb38e65a92 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -91,10 +91,22 @@ void machine__delete(struct machine *machine) free(machine); } -struct machine *machines__add(struct rb_root *machines, pid_t pid, +void machines__init(struct machines *machines) +{ + machine__init(&machines->host, "", HOST_KERNEL_ID); + machines->guests = RB_ROOT; +} + +void machines__exit(struct machines *machines) +{ + machine__exit(&machines->host); + /* XXX exit guest */ +} + +struct machine *machines__add(struct machines *machines, pid_t pid, const char *root_dir) { - struct rb_node **p = &machines->rb_node; + struct rb_node **p = &machines->guests.rb_node; struct rb_node *parent = NULL; struct machine *pos, *machine = malloc(sizeof(*machine)); @@ -116,18 +128,21 @@ struct machine *machines__add(struct rb_root *machines, pid_t pid, } rb_link_node(&machine->rb_node, parent, p); - rb_insert_color(&machine->rb_node, machines); + rb_insert_color(&machine->rb_node, &machines->guests); return machine; } -struct machine *machines__find(struct rb_root *machines, pid_t pid) +struct machine *machines__find(struct machines *machines, pid_t pid) { - struct rb_node **p = &machines->rb_node; + struct rb_node **p = &machines->guests.rb_node; struct rb_node *parent = NULL; struct machine *machine; struct machine *default_machine = NULL; + if (pid == HOST_KERNEL_ID) + return &machines->host; + while (*p != NULL) { parent = *p; machine = rb_entry(parent, struct machine, rb_node); @@ -144,7 +159,7 @@ struct machine *machines__find(struct rb_root *machines, pid_t pid) return default_machine; } -struct machine *machines__findnew(struct rb_root *machines, pid_t pid) +struct machine *machines__findnew(struct machines *machines, pid_t pid) { char path[PATH_MAX]; const char *root_dir = ""; @@ -178,12 +193,12 @@ out: return machine; } -void machines__process(struct rb_root *machines, - machine__process_t process, void *data) +void machines__process_guests(struct machines *machines, + machine__process_t process, void *data) { struct rb_node *nd; - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); process(pos, data); } @@ -203,12 +218,14 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size) return bf; } -void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) +void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) { struct rb_node *node; struct machine *machine; - for (node = rb_first(machines); node; node = rb_next(node)) { + machines->host.id_hdr_size = id_hdr_size; + + for (node = rb_first(&machines->guests); node; node = rb_next(node)) { machine = rb_entry(node, struct machine, rb_node); machine->id_hdr_size = id_hdr_size; } @@ -313,12 +330,13 @@ struct map *machine__new_module(struct machine *machine, u64 start, return map; } -size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) +size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) { struct rb_node *nd; - size_t ret = 0; + size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + + __dsos__fprintf(&machines->host.user_dsos, fp); - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += __dsos__fprintf(&pos->kernel_dsos, fp); ret += __dsos__fprintf(&pos->user_dsos, fp); @@ -334,13 +352,13 @@ size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); } -size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, +size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { struct rb_node *nd; - size_t ret = 0; + size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); - for (nd = rb_first(machines); nd; nd = rb_next(nd)) { + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { struct machine *pos = rb_entry(nd, struct machine, rb_node); ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); } @@ -511,7 +529,7 @@ void machine__destroy_kernel_maps(struct machine *machine) } } -int machines__create_guest_kernel_maps(struct rb_root *machines) +int machines__create_guest_kernel_maps(struct machines *machines) { int ret = 0; struct dirent **namelist = NULL; @@ -560,20 +578,22 @@ failure: return ret; } -void machines__destroy_guest_kernel_maps(struct rb_root *machines) +void machines__destroy_kernel_maps(struct machines *machines) { - struct rb_node *next = rb_first(machines); + struct rb_node *next = rb_first(&machines->guests); + + machine__destroy_kernel_maps(&machines->host); while (next) { struct machine *pos = rb_entry(next, struct machine, rb_node); next = rb_next(&pos->rb_node); - rb_erase(&pos->rb_node, machines); + rb_erase(&pos->rb_node, &machines->guests); machine__delete(pos); } } -int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) +int machines__create_kernel_maps(struct machines *machines, pid_t pid) { struct machine *machine = machines__findnew(machines, pid); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index e11236878ec1..5ac5892f2326 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -47,16 +47,24 @@ int machine__process_event(struct machine *machine, union perf_event *event); typedef void (*machine__process_t)(struct machine *machine, void *data); -void machines__process(struct rb_root *machines, - machine__process_t process, void *data); +struct machines { + struct machine host; + struct rb_root guests; +}; + +void machines__init(struct machines *machines); +void machines__exit(struct machines *machines); + +void machines__process_guests(struct machines *machines, + machine__process_t process, void *data); -struct machine *machines__add(struct rb_root *machines, pid_t pid, +struct machine *machines__add(struct machines *machines, pid_t pid, const char *root_dir); -struct machine *machines__find_host(struct rb_root *machines); -struct machine *machines__find(struct rb_root *machines, pid_t pid); -struct machine *machines__findnew(struct rb_root *machines, pid_t pid); +struct machine *machines__find_host(struct machines *machines); +struct machine *machines__find(struct machines *machines, pid_t pid); +struct machine *machines__findnew(struct machines *machines, pid_t pid); -void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size); +void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); char *machine__mmap_name(struct machine *machine, char *bf, size_t size); int machine__init(struct machine *machine, const char *root_dir, pid_t pid); @@ -132,17 +140,17 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type, size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); -size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp); -size_t machines__fprintf_dsos_buildid(struct rb_root *machines, FILE *fp, +size_t machines__fprintf_dsos(struct machines *machines, FILE *fp); +size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm); void machine__destroy_kernel_maps(struct machine *machine); int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); int machine__create_kernel_maps(struct machine *machine); -int machines__create_kernel_maps(struct rb_root *machines, pid_t pid); -int machines__create_guest_kernel_maps(struct rb_root *machines); -void machines__destroy_guest_kernel_maps(struct rb_root *machines); +int machines__create_kernel_maps(struct machines *machines, pid_t pid); +int machines__create_guest_kernel_maps(struct machines *machines); +void machines__destroy_kernel_maps(struct machines *machines); size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index b0bcc328d1fb..046b057c8f7f 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -86,13 +86,12 @@ void perf_session__set_id_hdr_size(struct perf_session *session) { u16 id_hdr_size = perf_evlist__id_hdr_size(session->evlist); - session->host_machine.id_hdr_size = id_hdr_size; machines__set_id_hdr_size(&session->machines, id_hdr_size); } int perf_session__create_kernel_maps(struct perf_session *self) { - int ret = machine__create_kernel_maps(&self->host_machine); + int ret = machine__create_kernel_maps(&self->machines.host); if (ret >= 0) ret = machines__create_guest_kernel_maps(&self->machines); @@ -101,8 +100,7 @@ int perf_session__create_kernel_maps(struct perf_session *self) static void perf_session__destroy_kernel_maps(struct perf_session *self) { - machine__destroy_kernel_maps(&self->host_machine); - machines__destroy_guest_kernel_maps(&self->machines); + machines__destroy_kernel_maps(&self->machines); } struct perf_session *perf_session__new(const char *filename, int mode, @@ -127,12 +125,11 @@ struct perf_session *perf_session__new(const char *filename, int mode, goto out; memcpy(self->filename, filename, len); - self->machines = RB_ROOT; self->repipe = repipe; INIT_LIST_HEAD(&self->ordered_samples.samples); INIT_LIST_HEAD(&self->ordered_samples.sample_cache); INIT_LIST_HEAD(&self->ordered_samples.to_free); - machine__init(&self->host_machine, "", HOST_KERNEL_ID); + machines__init(&self->machines); if (mode == O_RDONLY) { if (perf_session__open(self, force) < 0) @@ -162,12 +159,12 @@ out_delete: static void perf_session__delete_dead_threads(struct perf_session *session) { - machine__delete_dead_threads(&session->host_machine); + machine__delete_dead_threads(&session->machines.host); } static void perf_session__delete_threads(struct perf_session *session) { - machine__delete_threads(&session->host_machine); + machine__delete_threads(&session->machines.host); } static void perf_session_env__delete(struct perf_session_env *env) @@ -192,7 +189,7 @@ void perf_session__delete(struct perf_session *self) perf_session__delete_dead_threads(self); perf_session__delete_threads(self); perf_session_env__delete(&self->header.env); - machine__exit(&self->host_machine); + machines__exit(&self->machines); close(self->fd); free(self); vdso__exit(); @@ -998,7 +995,7 @@ void perf_event_header__bswap(struct perf_event_header *self) struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) { - return machine__findnew_thread(&session->host_machine, pid); + return machine__findnew_thread(&session->machines.host, pid); } static struct thread *perf_session__register_idle_thread(struct perf_session *self) @@ -1335,16 +1332,13 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps, size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) { - return __dsos__fprintf(&self->host_machine.kernel_dsos, fp) + - __dsos__fprintf(&self->host_machine.user_dsos, fp) + - machines__fprintf_dsos(&self->machines, fp); + return machines__fprintf_dsos(&self->machines, fp); } size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, bool (skip)(struct dso *dso, int parm), int parm) { - size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, skip, parm); - return ret + machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); + return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); } size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) @@ -1368,7 +1362,7 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) * FIXME: Here we have to actually print all the machines in this * session, not just the host... */ - return machine__fprintf(&session->host_machine, fp); + return machine__fprintf(&session->machines.host, fp); } void perf_session__remove_thread(struct perf_session *session, @@ -1377,10 +1371,10 @@ void perf_session__remove_thread(struct perf_session *session, /* * FIXME: This one makes no sense, we need to remove the thread from * the machine it belongs to, perf_session can have many machines, so - * doing it always on ->host_machine is wrong. Fix when auditing all + * doing it always on ->machines.host is wrong. Fix when auditing all * the 'perf kvm' code. */ - machine__remove_thread(&session->host_machine, th); + machine__remove_thread(&session->machines.host, th); } struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 57066cb867a6..de4e68716626 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -30,8 +30,7 @@ struct ordered_samples { struct perf_session { struct perf_header header; unsigned long size; - struct machine host_machine; - struct rb_root machines; + struct machines machines; struct perf_evlist *evlist; struct pevent *pevent; struct events_stats stats; @@ -49,7 +48,7 @@ struct perf_tool; struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, struct perf_tool *tool); -void perf_session__delete(struct perf_session *self); +void perf_session__delete(struct perf_session *session); void perf_event_header__bswap(struct perf_event_header *self); @@ -78,22 +77,18 @@ void perf_session__remove_thread(struct perf_session *self, struct thread *th); static inline struct machine *perf_session__find_host_machine(struct perf_session *self) { - return &self->host_machine; + return &self->machines.host; } static inline struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) { - if (pid == HOST_KERNEL_ID) - return &self->host_machine; return machines__find(&self->machines, pid); } static inline struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) { - if (pid == HOST_KERNEL_ID) - return &self->host_machine; return machines__findnew(&self->machines, pid); } -- cgit v1.2.3 From 34ba5122bf198c9cdfcbecc9b23eaa414244a3f6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 19 Dec 2012 09:04:24 -0300 Subject: perf machine: Simplify accessing the host machine It is always there, no sense in calling a function named "perf_session__find_host_machine". Also no sense in checking if that function return is NULL, so ditch needless error handling. Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-a6a3zx3afbrxo8p2zqm5mxo8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 7 +------ tools/perf/builtin-record.c | 7 +------ tools/perf/builtin-top.c | 4 ++-- tools/perf/util/session.c | 2 +- tools/perf/util/session.h | 6 ------ 5 files changed, 5 insertions(+), 21 deletions(-) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 0b4b796167be..9fddca749ca2 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -340,7 +340,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session, int n_lines, int is_caller) { struct rb_node *next; - struct machine *machine; + struct machine *machine = &session->machines.host; printf("%.102s\n", graph_dotted_line); printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr"); @@ -349,11 +349,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session, next = rb_first(root); - machine = perf_session__find_host_machine(session); - if (!machine) { - pr_err("__print_result: couldn't find kernel information\n"); - return; - } while (next && n_lines--) { struct alloc_stat *data = rb_entry(next, struct alloc_stat, node); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a0b2427b509d..2ac690cad411 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -512,12 +512,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) rec->post_processing_offset = lseek(output, 0, SEEK_CUR); - machine = perf_session__find_host_machine(session); - if (!machine) { - pr_err("Couldn't find native kernel information.\n"); - err = -1; - goto out_delete_session; - } + machine = &session->machines.host; if (opts->pipe_output) { err = perf_event__synthesize_attrs(tool, session, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e0ecebdde3fe..bc788126397b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -847,13 +847,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) ++top->us_samples; if (top->hide_user_symbols) continue; - machine = perf_session__find_host_machine(session); + machine = &session->machines.host; break; case PERF_RECORD_MISC_KERNEL: ++top->kernel_samples; if (top->hide_kernel_symbols) continue; - machine = perf_session__find_host_machine(session); + machine = &session->machines.host; break; case PERF_RECORD_MISC_GUEST_KERNEL: ++top->guest_kernel_samples; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 046b057c8f7f..bd85280bb6e8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -821,7 +821,7 @@ static struct machine * return perf_session__findnew_machine(session, pid); } - return perf_session__find_host_machine(session); + return &session->machines.host; } static int perf_session_deliver_event(struct perf_session *session, diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index de4e68716626..b5c0847edfa9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -74,12 +74,6 @@ int perf_session__create_kernel_maps(struct perf_session *self); void perf_session__set_id_hdr_size(struct perf_session *session); void perf_session__remove_thread(struct perf_session *self, struct thread *th); -static inline -struct machine *perf_session__find_host_machine(struct perf_session *self) -{ - return &self->machines.host; -} - static inline struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) { -- cgit v1.2.3 From a8bb559bd4eff5c71601e2e61a4bd1deef44a03c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Jan 2013 18:09:31 +0900 Subject: perf header: Add HEADER_GROUP_DESC feature Save group relationship information so that it can be restored when perf report is running. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1358845787-1350-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 3 + tools/perf/util/header.c | 164 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 2 + 3 files changed, 169 insertions(+) (limited to 'tools/perf/builtin-record.c') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 2ac690cad411..774c90713a53 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -486,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) goto out_delete_session; } + if (!evsel_list->nr_groups) + perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); + /* * perf_session__delete(session) will be called at perf_record__exit() */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f6081cb3fca3..8022b5254f75 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1084,6 +1084,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused, return 0; } +/* + * File format: + * + * struct group_descs { + * u32 nr_groups; + * struct group_desc { + * char name[]; + * u32 leader_idx; + * u32 nr_members; + * }[nr_groups]; + * }; + */ +static int write_group_desc(int fd, struct perf_header *h __maybe_unused, + struct perf_evlist *evlist) +{ + u32 nr_groups = evlist->nr_groups; + struct perf_evsel *evsel; + int ret; + + ret = do_write(fd, &nr_groups, sizeof(nr_groups)); + if (ret < 0) + return ret; + + list_for_each_entry(evsel, &evlist->entries, node) { + if (perf_evsel__is_group_leader(evsel) && + evsel->nr_members > 1) { + const char *name = evsel->group_name ?: "{anon_group}"; + u32 leader_idx = evsel->idx; + u32 nr_members = evsel->nr_members; + + ret = do_write_string(fd, name); + if (ret < 0) + return ret; + + ret = do_write(fd, &leader_idx, sizeof(leader_idx)); + if (ret < 0) + return ret; + + ret = do_write(fd, &nr_members, sizeof(nr_members)); + if (ret < 0) + return ret; + } + } + return 0; +} + /* * default get_cpuid(): nothing gets recorded * actual implementation must be in arch/$(ARCH)/util/header.c @@ -1447,6 +1493,31 @@ error: fprintf(fp, "# pmu mappings: unable to read\n"); } +static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, + FILE *fp) +{ + struct perf_session *session; + struct perf_evsel *evsel; + u32 nr = 0; + + session = container_of(ph, struct perf_session, header); + + list_for_each_entry(evsel, &session->evlist->entries, node) { + if (perf_evsel__is_group_leader(evsel) && + evsel->nr_members > 1) { + fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", + perf_evsel__name(evsel)); + + nr = evsel->nr_members - 1; + } else if (nr) { + fprintf(fp, ",%s", perf_evsel__name(evsel)); + + if (--nr == 0) + fprintf(fp, "}\n"); + } + } +} + static int __event_process_build_id(struct build_id_event *bev, char *filename, struct perf_session *session) @@ -1961,6 +2032,98 @@ error: return -1; } +static int process_group_desc(struct perf_file_section *section __maybe_unused, + struct perf_header *ph, int fd, + void *data __maybe_unused) +{ + size_t ret = -1; + u32 i, nr, nr_groups; + struct perf_session *session; + struct perf_evsel *evsel, *leader = NULL; + struct group_desc { + char *name; + u32 leader_idx; + u32 nr_members; + } *desc; + + if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups)) + return -1; + + if (ph->needs_swap) + nr_groups = bswap_32(nr_groups); + + ph->env.nr_groups = nr_groups; + if (!nr_groups) { + pr_debug("group desc not available\n"); + return 0; + } + + desc = calloc(nr_groups, sizeof(*desc)); + if (!desc) + return -1; + + for (i = 0; i < nr_groups; i++) { + desc[i].name = do_read_string(fd, ph); + if (!desc[i].name) + goto out_free; + + if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32)) + goto out_free; + + if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32)) + goto out_free; + + if (ph->needs_swap) { + desc[i].leader_idx = bswap_32(desc[i].leader_idx); + desc[i].nr_members = bswap_32(desc[i].nr_members); + } + } + + /* + * Rebuild group relationship based on the group_desc + */ + session = container_of(ph, struct perf_session, header); + session->evlist->nr_groups = nr_groups; + + i = nr = 0; + list_for_each_entry(evsel, &session->evlist->entries, node) { + if (evsel->idx == (int) desc[i].leader_idx) { + evsel->leader = evsel; + /* {anon_group} is a dummy name */ + if (strcmp(desc[i].name, "{anon_group}")) + evsel->group_name = desc[i].name; + evsel->nr_members = desc[i].nr_members; + + if (i >= nr_groups || nr > 0) { + pr_debug("invalid group desc\n"); + goto out_free; + } + + leader = evsel; + nr = evsel->nr_members - 1; + i++; + } else if (nr) { + /* This is a group member */ + evsel->leader = leader; + + nr--; + } + } + + if (i != nr_groups || nr != 0) { + pr_debug("invalid group desc\n"); + goto out_free; + } + + ret = 0; +out_free: + while ((int) --i >= 0) + free(desc[i].name); + free(desc); + + return ret; +} + struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); @@ -2000,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), + FEAT_OPP(HEADER_GROUP_DESC, group_desc), }; struct header_print_data { diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 20f0344accb1..c9fc55cada6d 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -29,6 +29,7 @@ enum { HEADER_NUMA_TOPOLOGY, HEADER_BRANCH_STACK, HEADER_PMU_MAPPINGS, + HEADER_GROUP_DESC, HEADER_LAST_FEATURE, HEADER_FEAT_BITS = 256, }; @@ -79,6 +80,7 @@ struct perf_session_env { char *numa_nodes; int nr_pmu_mappings; char *pmu_mappings; + int nr_groups; }; struct perf_header { -- cgit v1.2.3