diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-10-15 11:54:14 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-10-15 11:54:14 +0200 |
commit | ec4212d88a77eb6caec10777ddd629b702a5ebbd (patch) | |
tree | 03b4b08df9d633e15df8c0ff27444324adf4a312 /tools/perf | |
parent | 77654908ff1a58cee4886298968b5262884aff0b (diff) | |
parent | 2c241bd35e6f626ad6f867dcf9fefdc2315f125f (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
Infrastructure fixes and changes:
* Fix off-by-one bugs in map->end handling (Stephane Eranian)
* Fix off-by-one bug in maps__find(), also related to map->end handling (Namhyung Kim)
* Make struct symbol->end be the first addr after the symbol range, to make it
match the convention used for struct map->end. (Arnaldo Carvalho de Melo)
* Fix perf_evlist__add_pollfd() error handling in 'perf kvm stat live' (Jiri Olsa)
* Fix python test build by moving callchain_param to an object linked into the
python binding (Jiri Olsa)
* Do not include a struct hists per perf_evsel, untangling the histogram code
from perf_evsel, to pave the way for exporting a minimalistic
tools/lib/api/perf/ library usable by tools/perf and initially by the rasd
daemon being developed by Borislav Petkov, Robert Richter and Jean Pihet.
(Arnaldo Carvalho de Melo)
* Make perf_evlist__open(evlist, NULL, NULL), i.e. without cpu and thread
maps mean syswide monitoring, reducing the boilerplate for tools that
only want system wide mode. (Arnaldo Carvalho de Melo)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
35 files changed, 392 insertions, 229 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index be5939418425..e7417fe97a97 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -51,6 +51,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, struct addr_location *al, struct perf_annotate *ann) { + struct hists *hists = evsel__hists(evsel); struct hist_entry *he; int ret; @@ -66,13 +67,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, return 0; } - he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0, - true); + he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true); if (he == NULL) return -ENOMEM; ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); - hists__inc_nr_samples(&evsel->hists, true); + hists__inc_nr_samples(hists, true); return ret; } @@ -214,6 +214,7 @@ static int __cmd_annotate(struct perf_annotate *ann) if (dump_trace) { perf_session__fprintf_nr_events(session, stdout); + perf_evlist__fprintf_nr_events(session->evlist, stdout); goto out; } @@ -225,7 +226,7 @@ static int __cmd_annotate(struct perf_annotate *ann) total_nr_samples = 0; evlist__for_each(session->evlist, pos) { - struct hists *hists = &pos->hists; + struct hists *hists = evsel__hists(pos); u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; if (nr_samples > 0) { @@ -325,7 +326,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) "Show event group information together"), OPT_END() }; - int ret; + int ret = hists__init(); + + if (ret < 0) + return ret; argc = parse_options(argc, argv, options, annotate_usage, 0); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index a3ce19f7aebd..8c5c11ca8c53 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -327,6 +327,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, struct machine *machine) { struct addr_location al; + struct hists *hists = evsel__hists(evsel); if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { pr_warning("problem processing %d event, skipping it.\n", @@ -334,7 +335,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, return -1; } - if (hists__add_entry(&evsel->hists, &al, sample->period, + if (hists__add_entry(hists, &al, sample->period, sample->weight, sample->transaction)) { pr_warning("problem incrementing symbol period, skipping event\n"); return -1; @@ -346,9 +347,9 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, * hists__output_resort() and precompute needs the total * period in order to sort entries by percentage delta. */ - evsel->hists.stats.total_period += sample->period; + hists->stats.total_period += sample->period; if (!al.filtered) - evsel->hists.stats.total_non_filtered_period += sample->period; + hists->stats.total_non_filtered_period += sample->period; return 0; } @@ -382,7 +383,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) struct perf_evsel *evsel; evlist__for_each(evlist, evsel) { - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); } @@ -631,24 +632,26 @@ static void data_process(void) bool first = true; evlist__for_each(evlist_base, evsel_base) { + struct hists *hists_base = evsel__hists(evsel_base); struct data__file *d; int i; data__for_each_file_new(i, d) { struct perf_evlist *evlist = d->session->evlist; struct perf_evsel *evsel; + struct hists *hists; evsel = evsel_match(evsel_base, evlist); if (!evsel) continue; - d->hists = &evsel->hists; + hists = evsel__hists(evsel); + d->hists = hists; - hists__match(&evsel_base->hists, &evsel->hists); + hists__match(hists_base, hists); if (!show_baseline_only) - hists__link(&evsel_base->hists, - &evsel->hists); + hists__link(hists_base, hists); } fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", @@ -659,7 +662,7 @@ static void data_process(void) if (verbose || data__files_cnt > 2) data__fprintf(); - hists__process(&evsel_base->hists); + hists__process(hists_base); } } diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index d8bf2271f4ea..460a4ce9c044 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -896,8 +896,7 @@ static int perf_kvm__handle_stdin(void) static int kvm_events_live_report(struct perf_kvm_stat *kvm) { - struct pollfd *pollfds = NULL; - int nr_fds, nr_stdin, ret, err = -EINVAL; + int nr_stdin, ret, err = -EINVAL; struct termios save; /* live flag must be set first */ @@ -919,34 +918,27 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); - /* use pollfds -- need to add timerfd and stdin */ - nr_fds = kvm->evlist->pollfd.nr; - /* add timer fd */ if (perf_kvm__timerfd_create(kvm) < 0) { err = -1; goto out; } - if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd)) + if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0) goto out; - nr_fds++; - - if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin))) + nr_stdin = perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)); + if (nr_stdin < 0) goto out; - nr_stdin = nr_fds; - nr_fds++; if (fd_set_nonblock(fileno(stdin)) != 0) goto out; - pollfds = kvm->evlist->pollfd.entries; - /* everything is good - enable the events and process */ perf_evlist__enable(kvm->evlist); while (!done) { + struct fdarray *fda = &kvm->evlist->pollfd; int rc; rc = perf_kvm__mmap_read(kvm); @@ -957,11 +949,11 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) if (err) goto out; - if (pollfds[nr_stdin].revents & POLLIN) + if (fda->entries[nr_stdin].revents & POLLIN) done = perf_kvm__handle_stdin(); if (!rc && !done) - err = poll(pollfds, nr_fds, 100); + err = fdarray__poll(fda, 100); } perf_evlist__disable(kvm->evlist); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 44c6f3d55ce7..a6b2132c666f 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -14,6 +14,7 @@ #include "util/parse-options.h" #include "util/parse-events.h" +#include "util/callchain.h" #include "util/header.h" #include "util/event.h" #include "util/evlist.h" diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ac145fae0521..2cfc4b93991f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -288,12 +288,14 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report evname = buf; for_each_group_member(pos, evsel) { + const struct hists *pos_hists = evsel__hists(pos); + if (symbol_conf.filter_relative) { - nr_samples += pos->hists.stats.nr_non_filtered_samples; - nr_events += pos->hists.stats.total_non_filtered_period; + nr_samples += pos_hists->stats.nr_non_filtered_samples; + nr_events += pos_hists->stats.total_non_filtered_period; } else { - nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; - nr_events += pos->hists.stats.total_period; + nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; + nr_events += pos_hists->stats.total_period; } } } @@ -318,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, struct perf_evsel *pos; evlist__for_each(evlist, pos) { - struct hists *hists = &pos->hists; + struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); if (symbol_conf.event_group && @@ -427,7 +429,7 @@ static void report__collapse_hists(struct report *rep) ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); evlist__for_each(rep->session->evlist, pos) { - struct hists *hists = &pos->hists; + struct hists *hists = evsel__hists(pos); if (pos->idx == 0) hists->symbol_filter_str = rep->symbol_filter_str; @@ -437,7 +439,7 @@ static void report__collapse_hists(struct report *rep) /* Non-group events are considered as leader */ if (symbol_conf.event_group && !perf_evsel__is_group_leader(pos)) { - struct hists *leader_hists = &pos->leader->hists; + struct hists *leader_hists = evsel__hists(pos->leader); hists__match(leader_hists, hists); hists__link(leader_hists, hists); @@ -485,6 +487,7 @@ static int __cmd_report(struct report *rep) if (dump_trace) { perf_session__fprintf_nr_events(session, stdout); + perf_evlist__fprintf_nr_events(session->evlist, stdout); return 0; } } @@ -500,7 +503,7 @@ static int __cmd_report(struct report *rep) } evlist__for_each(session->evlist, pos) - hists__output_resort(&pos->hists); + hists__output_resort(evsel__hists(pos)); return report__browse_hists(rep); } @@ -565,7 +568,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) struct stat st; bool has_br_stack = false; int branch_mode = -1; - int ret = -1; char callchain_default_opt[] = "fractal,0.5,callee"; const char * const report_usage[] = { "perf report [<options>]", @@ -692,6 +694,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) struct perf_data_file file = { .mode = PERF_DATA_MODE_READ, }; + int ret = hists__init(); + + if (ret < 0) + return ret; perf_config(report__config, &report); diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 9c9287fbf8e9..891c3930080e 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1431,9 +1431,6 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ { int err = 0; - evsel->hists.stats.total_period += sample->period; - hists__inc_nr_samples(&evsel->hists, true); - if (evsel->handler != NULL) { tracepoint_handler f = evsel->handler; err = f(tool, evsel, sample, machine); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b9b9e58a6c39..6b4925f65bf0 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -572,7 +572,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, scripting_ops->process_event(event, sample, evsel, thread, &al); - evsel->hists.stats.total_period += sample->period; return 0; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fc3d55f832ac..0aa7747ff139 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -251,6 +251,7 @@ static void perf_top__print_sym_table(struct perf_top *top) char bf[160]; int printed = 0; const int win_width = top->winsize.ws_col - 1; + struct hists *hists = evsel__hists(top->sym_evsel); puts(CONSOLE_CLEAR); @@ -261,13 +262,13 @@ static void perf_top__print_sym_table(struct perf_top *top) printf("%-*.*s\n", win_width, win_width, graph_dotted_line); - if (top->sym_evsel->hists.stats.nr_lost_warned != - top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { - top->sym_evsel->hists.stats.nr_lost_warned = - top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; + if (hists->stats.nr_lost_warned != + hists->stats.nr_events[PERF_RECORD_LOST]) { + hists->stats.nr_lost_warned = + hists->stats.nr_events[PERF_RECORD_LOST]; color_fprintf(stdout, PERF_COLOR_RED, "WARNING: LOST %d chunks, Check IO/CPU overload", - top->sym_evsel->hists.stats.nr_lost_warned); + hists->stats.nr_lost_warned); ++printed; } @@ -277,21 +278,18 @@ static void perf_top__print_sym_table(struct perf_top *top) } if (top->zero) { - hists__delete_entries(&top->sym_evsel->hists); + hists__delete_entries(hists); } else { - hists__decay_entries(&top->sym_evsel->hists, - top->hide_user_symbols, + hists__decay_entries(hists, top->hide_user_symbols, top->hide_kernel_symbols); } - hists__collapse_resort(&top->sym_evsel->hists, NULL); - hists__output_resort(&top->sym_evsel->hists); + hists__collapse_resort(hists, NULL); + hists__output_resort(hists); - hists__output_recalc_col_len(&top->sym_evsel->hists, - top->print_entries - printed); + hists__output_recalc_col_len(hists, top->print_entries - printed); putchar('\n'); - hists__fprintf(&top->sym_evsel->hists, false, - top->print_entries - printed, win_width, + hists__fprintf(hists, false, top->print_entries - printed, win_width, top->min_percent, stdout); } @@ -334,6 +332,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) { char *buf = malloc(0), *p; struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; + struct hists *hists = evsel__hists(top->sym_evsel); struct rb_node *next; size_t dummy = 0; @@ -351,7 +350,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) if (p) *p = 0; - next = rb_first(&top->sym_evsel->hists.entries); + next = rb_first(&hists->entries); while (next) { n = rb_entry(next, struct hist_entry, rb_node); if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { @@ -538,21 +537,24 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) static void perf_top__sort_new_samples(void *arg) { struct perf_top *t = arg; + struct hists *hists; + perf_top__reset_sample_counters(t); if (t->evlist->selected != NULL) t->sym_evsel = t->evlist->selected; + hists = evsel__hists(t->sym_evsel); + if (t->zero) { - hists__delete_entries(&t->sym_evsel->hists); + hists__delete_entries(hists); } else { - hists__decay_entries(&t->sym_evsel->hists, - t->hide_user_symbols, + hists__decay_entries(hists, t->hide_user_symbols, t->hide_kernel_symbols); } - hists__collapse_resort(&t->sym_evsel->hists, NULL); - hists__output_resort(&t->sym_evsel->hists); + hists__collapse_resort(hists, NULL); + hists__output_resort(hists); } static void *display_thread_tui(void *arg) @@ -573,8 +575,10 @@ static void *display_thread_tui(void *arg) * Zooming in/out UIDs. For now juse use whatever the user passed * via --uid. */ - evlist__for_each(top->evlist, pos) - pos->hists.uid_filter_str = top->record_opts.target.uid_str; + evlist__for_each(top->evlist, pos) { + struct hists *hists = evsel__hists(pos); + hists->uid_filter_str = top->record_opts.target.uid_str; + } perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, &top->session->header.env); @@ -768,6 +772,7 @@ static void perf_event__process_sample(struct perf_tool *tool, } if (al.sym == NULL || !al.sym->ignore) { + struct hists *hists = evsel__hists(evsel); struct hist_entry_iter iter = { .add_entry_cb = hist_iter__top_callback, }; @@ -777,14 +782,14 @@ static void perf_event__process_sample(struct perf_tool *tool, else iter.ops = &hist_iter_normal; - pthread_mutex_lock(&evsel->hists.lock); + pthread_mutex_lock(&hists->lock); err = hist_entry_iter__add(&iter, &al, evsel, sample, top->max_stack, top); if (err < 0) pr_err("Problem incrementing symbol period, skipping event\n"); - pthread_mutex_unlock(&evsel->hists.lock); + pthread_mutex_unlock(&hists->lock); } return; @@ -849,7 +854,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) perf_event__process_sample(&top->tool, event, evsel, &sample, machine); } else if (event->header.type < PERF_RECORD_MAX) { - hists__inc_nr_events(&evsel->hists, event->header.type); + hists__inc_nr_events(evsel__hists(evsel), event->header.type); machine__process_event(machine, event, &sample); } else ++session->stats.nr_unknown_events; @@ -1042,7 +1047,6 @@ parse_percent_limit(const struct option *opt, const char *arg, int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) { - int status = -1; char errbuf[BUFSIZ]; struct perf_top top = { .count_filter = 5, @@ -1160,6 +1164,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) "perf top [<options>]", NULL }; + int status = hists__init(); + + if (status < 0) + return status; top.evlist = perf_evlist__new(); if (top.evlist == NULL) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index ac655b0700e7..162c978f1491 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -6,6 +6,7 @@ #include <unistd.h> #include <string.h> #include "builtin.h" +#include "hist.h" #include "intlist.h" #include "tests.h" #include "debug.h" @@ -302,6 +303,10 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) OPT_END() }; struct intlist *skiplist = NULL; + int ret = hists__init(); + + if (ret < 0) + return ret; argc = parse_options(argc, argv, test_options, test_usage, 0); if (argc >= 1 && !strcmp(argv[0], "list")) diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index 0ac240db2e24..614d5c4978ab 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c @@ -245,7 +245,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec static int test1(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); /* * expected output: * @@ -295,7 +295,7 @@ out: static int test2(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); /* * expected output: * @@ -442,7 +442,7 @@ out: static int test3(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); /* * expected output: * @@ -498,7 +498,7 @@ out: static int test4(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); /* * expected output: * diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index 821f581fd930..5a31787cc6b9 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -66,11 +66,12 @@ static int add_hist_entries(struct perf_evlist *evlist, .ops = &hist_iter_normal, .hide_unresolved = false, }; + struct hists *hists = evsel__hists(evsel); /* make sure it has no filter at first */ - evsel->hists.thread_filter = NULL; - evsel->hists.dso_filter = NULL; - evsel->hists.symbol_filter_str = NULL; + hists->thread_filter = NULL; + hists->dso_filter = NULL; + hists->symbol_filter_str = NULL; sample.pid = fake_samples[i].pid; sample.tid = fake_samples[i].pid; @@ -134,7 +135,7 @@ int test__hists_filter(void) goto out; evlist__for_each(evlist, evsel) { - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); hists__collapse_resort(hists, NULL); hists__output_resort(hists); @@ -160,7 +161,7 @@ int test__hists_filter(void) hists->stats.total_non_filtered_period); /* now applying thread filter for 'bash' */ - evsel->hists.thread_filter = fake_samples[9].thread; + hists->thread_filter = fake_samples[9].thread; hists__filter_by_thread(hists); if (verbose > 2) { @@ -185,11 +186,11 @@ int test__hists_filter(void) hists->stats.total_non_filtered_period == 400); /* remove thread filter first */ - evsel->hists.thread_filter = NULL; + hists->thread_filter = NULL; hists__filter_by_thread(hists); /* now applying dso filter for 'kernel' */ - evsel->hists.dso_filter = fake_samples[0].map->dso; + hists->dso_filter = fake_samples[0].map->dso; hists__filter_by_dso(hists); if (verbose > 2) { @@ -214,7 +215,7 @@ int test__hists_filter(void) hists->stats.total_non_filtered_period == 300); /* remove dso filter first */ - evsel->hists.dso_filter = NULL; + hists->dso_filter = NULL; hists__filter_by_dso(hists); /* @@ -224,7 +225,7 @@ int test__hists_filter(void) * be counted as a separate entry but the sample count and * total period will be remained. */ - evsel->hists.symbol_filter_str = "main"; + hists->symbol_filter_str = "main"; hists__filter_by_symbol(hists); if (verbose > 2) { @@ -249,8 +250,8 @@ int test__hists_filter(void) hists->stats.total_non_filtered_period == 300); /* now applying all filters at once. */ - evsel->hists.thread_filter = fake_samples[1].thread; - evsel->hists.dso_filter = fake_samples[1].map->dso; + hists->thread_filter = fake_samples[1].thread; + hists->dso_filter = fake_samples[1].map->dso; hists__filter_by_thread(hists); hists__filter_by_dso(hists); diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index d4b34b0f50a2..278ba8344c23 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c @@ -73,6 +73,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) * "bash [libc] malloc" so total 9 entries will be in the tree. */ evlist__for_each(evlist, evsel) { + struct hists *hists = evsel__hists(evsel); + for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { const union perf_event event = { .header = { @@ -87,7 +89,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) &sample) < 0) goto out; - he = __hists__add_entry(&evsel->hists, &al, NULL, + he = __hists__add_entry(hists, &al, NULL, NULL, NULL, 1, 1, 0, true); if (he == NULL) goto out; @@ -111,7 +113,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) &sample) < 0) goto out; - he = __hists__add_entry(&evsel->hists, &al, NULL, + he = __hists__add_entry(hists, &al, NULL, NULL, NULL, 1, 1, 0, true); if (he == NULL) goto out; @@ -271,6 +273,7 @@ static int validate_link(struct hists *leader, struct hists *other) int test__hists_link(void) { int err = -1; + struct hists *hists, *first_hists; struct machines machines; struct machine *machine = NULL; struct perf_evsel *evsel, *first; @@ -306,24 +309,28 @@ int test__hists_link(void) goto out; evlist__for_each(evlist, evsel) { - hists__collapse_resort(&evsel->hists, NULL); + hists = evsel__hists(evsel); + hists__collapse_resort(hists, NULL); if (verbose > 2) - print_hists_in(&evsel->hists); + print_hists_in(hists); } first = perf_evlist__first(evlist); evsel = perf_evlist__last(evlist); + first_hists = evsel__hists(first); + hists = evsel__hists(evsel); + /* match common entries */ - hists__match(&first->hists, &evsel->hists); - err = validate_match(&first->hists, &evsel->hists); + hists__match(first_hists, hists); + err = validate_match(first_hists, hists); if (err) goto out; /* link common and/or dummy entries */ - hists__link(&first->hists, &evsel->hists); - err = validate_link(&first->hists, &evsel->hists); + hists__link(first_hists, hists); + err = validate_link(first_hists, hists); if (err) goto out; diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index e3bbd6c54c1b..a748f2be1222 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c @@ -122,7 +122,7 @@ typedef int (*test_fn_t)(struct perf_evsel *, struct machine *); static int test1(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); struct hist_entry *he; struct rb_root *root; struct rb_node *node; @@ -159,7 +159,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine) print_hists_out(hists); } - root = &evsel->hists.entries; + root = &hists->entries; node = rb_first(root); he = rb_entry(node, struct hist_entry, rb_node); TEST_ASSERT_VAL("Invalid hist entry", @@ -224,7 +224,7 @@ out: static int test2(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); struct hist_entry *he; struct rb_root *root; struct rb_node *node; @@ -259,7 +259,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine) print_hists_out(hists); } - root = &evsel->hists.entries; + root = &hists->entries; node = rb_first(root); he = rb_entry(node, struct hist_entry, rb_node); TEST_ASSERT_VAL("Invalid hist entry", @@ -280,7 +280,7 @@ out: static int test3(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); struct hist_entry *he; struct rb_root *root; struct rb_node *node; @@ -313,7 +313,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) print_hists_out(hists); } - root = &evsel->hists.entries; + root = &hists->entries; node = rb_first(root); he = rb_entry(node, struct hist_entry, rb_node); TEST_ASSERT_VAL("Invalid hist entry", @@ -354,7 +354,7 @@ out: static int test4(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); struct hist_entry *he; struct rb_root *root; struct rb_node *node; @@ -391,7 +391,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) print_hists_out(hists); } - root = &evsel->hists.entries; + root = &hists->entries; node = rb_first(root); he = rb_entry(node, struct hist_entry, rb_node); TEST_ASSERT_VAL("Invalid hist entry", @@ -456,7 +456,7 @@ out: static int test5(struct perf_evsel *evsel, struct machine *machine) { int err; - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); struct hist_entry *he; struct rb_root *root; struct rb_node *node; @@ -494,7 +494,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine) print_hists_out(hists); } - root = &evsel->hists.entries; + root = &hists->entries; node = rb_first(root); he = rb_entry(node, struct hist_entry, rb_node); diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c index 89c16b988618..e8278c558d4a 100644 --- a/tools/perf/ui/browsers/header.c +++ b/tools/perf/ui/browsers/header.c @@ -1,6 +1,7 @@ #include "util/cache.h" #include "util/debug.h" #include "ui/browser.h" +#include "ui/keysyms.h" #include "ui/ui.h" #include "ui/util.h" #include "ui/libslang.h" diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 8f60a970404f..68eab9ea1634 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1229,12 +1229,14 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size) ev_name = buf; for_each_group_member(pos, evsel) { + struct hists *pos_hists = evsel__hists(pos); + if (symbol_conf.filter_relative) { - nr_samples += pos->hists.stats.nr_non_filtered_samples; - nr_events += pos->hists.stats.total_non_filtered_period; + nr_samples += pos_hists->stats.nr_non_filtered_samples; + nr_events += pos_hists->stats.total_non_filtered_period; } else { - nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; - nr_events += pos->hists.stats.total_period; + nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; + nr_events += pos_hists->stats.total_period; } } } @@ -1387,7 +1389,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, float min_pcnt, struct perf_session_env *env) { - struct hists *hists = &evsel->hists; + struct hists *hists = evsel__hists(evsel); struct hist_browser *browser = hist_browser__new(hists); struct branch_info *bi; struct pstack *fstack; @@ -1802,8 +1804,9 @@ static void perf_evsel_menu__write(struct ui_browser *browser, struct perf_evsel_menu *menu = container_of(browser, struct perf_evsel_menu, b); struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); + struct hists *hists = evsel__hists(evsel); bool current_entry = ui_browser__is_current_entry(browser, row); - unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; + unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE]; const char *ev_name = perf_evsel__name(evsel); char bf[256], unit; const char *warn = " "; @@ -1818,7 +1821,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser, ev_name = perf_evsel__group_name(evsel); for_each_group_member(pos, evsel) { - nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; + struct hists *pos_hists = evsel__hists(pos); + nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE]; } } @@ -1827,7 +1831,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, unit, unit == ' ' ? "" : " ", ev_name); slsmg_printf("%s", bf); - nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; + nr_events = hists->stats.nr_events[PERF_RECORD_LOST]; if (nr_events != 0) { menu->lost_events = true; if (!current_entry) diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index f3fa4258b256..fc654fb77ace 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -319,7 +319,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, gtk_container_add(GTK_CONTAINER(window), vbox); evlist__for_each(evlist, pos) { - struct hists *hists = &pos->hists; + struct hists *hists = evsel__hists(pos); const char *evname = perf_evsel__name(pos); GtkWidget *scrolled_window; GtkWidget *tab_label; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 36437527dbb3..7dabde14ea54 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -478,7 +478,7 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - if (addr < sym->start || addr > sym->end) + if (addr < sym->start || addr >= sym->end) return -ERANGE; offset = addr - sym->start; @@ -836,7 +836,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, end = map__rip_2objdump(map, sym->end); offset = line_ip - start; - if ((u64)line_ip < start || (u64)line_ip > end) + if ((u64)line_ip < start || (u64)line_ip >= end) offset = -1; else parsed_line = tmp2 + 1; @@ -966,7 +966,7 @@ fallback: kce.kcore_filename = symfs_filename; kce.addr = map__rip_2objdump(map, sym->start); kce.offs = sym->start; - kce.len = sym->end + 1 - sym->start; + kce.len = sym->end - sym->start; if (!kcore_extract__create(&kce)) { delete_extract = true; strlcpy(symfs_filename, kce.extract_filename, @@ -987,7 +987,7 @@ fallback: disassembler_style ? "-M " : "", disassembler_style ? disassembler_style : "", map__rip_2objdump(map, sym->start), - map__rip_2objdump(map, sym->end+1), + map__rip_2objdump(map, sym->end), symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", symbol_conf.annotate_src ? "-S" : "", symfs_filename, filename); diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 2a1f5a46543a..94cfefddf4db 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -65,6 +65,8 @@ struct callchain_param { enum chain_key key; }; +extern struct callchain_param callchain_param; + struct callchain_list { u64 ip; struct map_symbol ms; diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 7eb7107731ec..5699e7e2a790 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -190,6 +190,32 @@ enum perf_user_event_type { /* above any possible kernel type */ PERF_RECORD_HEADER_MAX }; +/* + * The kernel collects the number of events it couldn't send in a stretch and + * when possible sends this number in a PERF_RECORD_LOST event. The number of + * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while + * total_lost tells exactly how many events the kernel in fact lost, i.e. it is + * the sum of all struct lost_event.lost fields reported. + * + * The total_period is needed because by default auto-freq is used, so + * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get + * the total number of low level events, it is necessary to to sum all struct + * sample_event.period and stash the result in total_period. + */ +struct events_stats { + u64 total_period; + u64 total_non_filtered_period; + u64 total_lost; + u64 total_invalid_chains; + u32 nr_events[PERF_RECORD_HEADER_MAX]; + u32 nr_non_filtered_samples; + u32 nr_lost_warned; + u32 nr_unknown_events; + u32 nr_invalid_chains; + u32 nr_unknown_id; + u32 nr_unprocessable_samples; +}; + struct attr_event { struct perf_event_header header; struct perf_event_attr attr; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3cebc9a8d52e..b4b54d84e9b0 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1175,11 +1175,51 @@ void perf_evlist__close(struct perf_evlist *evlist) } } +static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) +{ + int err = -ENOMEM; + + /* + * Try reading /sys/devices/system/cpu/online to get + * an all cpus map. + * + * FIXME: -ENOMEM is the best we can do here, the cpu_map + * code needs an overhaul to properly forward the + * error, and we may not want to do that fallback to a + * default cpu identity map :-\ + */ + evlist->cpus = cpu_map__new(NULL); + if (evlist->cpus == NULL) + goto out; + + evlist->threads = thread_map__new_dummy(); + if (evlist->threads == NULL) + goto out_free_cpus; + + err = 0; +out: + return err; +out_free_cpus: + cpu_map__delete(evlist->cpus); + evlist->cpus = NULL; + goto out; +} + int perf_evlist__open(struct perf_evlist *evlist) { struct perf_evsel *evsel; int err; + /* + * Default: one fd per CPU, all threads, aka systemwide + * as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL + */ + if (evlist->threads == NULL && evlist->cpus == NULL) { + err = perf_evlist__create_syswide_maps(evlist); + if (err < 0) + goto out_err; + } + perf_evlist__update_id_pos(evlist); evlist__for_each(evlist, evsel) { @@ -1276,8 +1316,14 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar sigaction(SIGUSR1, &act, NULL); } - if (target__none(target)) + if (target__none(target)) { + if (evlist->threads == NULL) { + fprintf(stderr, "FATAL: evlist->threads need to be set at this point (%s:%d).\n", + __func__, __LINE__); + goto out_close_pipes; + } evlist->threads->map[0] = evlist->workload.pid; + } close(child_ready_pipe[1]); close(go_pipe[0]); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index e0868a901c4a..d1ecde0fd56c 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -15,6 +15,7 @@ #include <linux/perf_event.h> #include <sys/resource.h> #include "asm/bug.h" +#include "callchain.h" #include "evsel.h" #include "evlist.h" #include "util.h" @@ -32,6 +33,48 @@ static struct { bool cloexec; } perf_missing_features; +static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) +{ + return 0; +} + +static void perf_evsel__no_extra_fini(struct perf_evsel *evsel __maybe_unused) +{ +} + +static struct { + size_t size; + int (*init)(struct perf_evsel *evsel); + void (*fini)(struct perf_evsel *evsel); +} perf_evsel__object = { + .size = sizeof(struct perf_evsel), + .init = perf_evsel__no_extra_init, + .fini = perf_evsel__no_extra_fini, +}; + +int perf_evsel__object_config(size_t object_size, + int (*init)(struct perf_evsel *evsel), + void (*fini)(struct perf_evsel *evsel)) +{ + + if (object_size == 0) + goto set_methods; + + if (perf_evsel__object.size > object_size) + return -EINVAL; + + perf_evsel__object.size = object_size; + +set_methods: + if (init != NULL) + perf_evsel__object.init = init; + + if (fini != NULL) + perf_evsel__object.fini = fini; + + return 0; +} + #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) int __perf_evsel__sample_size(u64 sample_type) @@ -116,16 +159,6 @@ void perf_evsel__calc_id_pos(struct perf_evsel *evsel) evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type); } -void hists__init(struct hists *hists) -{ - memset(hists, 0, sizeof(*hists)); - hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; - hists->entries_in = &hists->entries_in_array[0]; - hists->entries_collapsed = RB_ROOT; - hists->entries = RB_ROOT; - pthread_mutex_init(&hists->lock, NULL); -} - void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, enum perf_event_sample_format bit) { @@ -168,14 +201,14 @@ void perf_evsel__init(struct perf_evsel *evsel, evsel->unit = ""; evsel->scale = 1.0; INIT_LIST_HEAD(&evsel->node); - hists__init(&evsel->hists); + perf_evsel__object.init(evsel); evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); perf_evsel__calc_id_pos(evsel); } struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) { - struct perf_evsel *evsel = zalloc(sizeof(*evsel)); + struct perf_evsel *evsel = zalloc(perf_evsel__object.size); if (evsel != NULL) perf_evsel__init(evsel, attr, idx); @@ -185,7 +218,7 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) { - struct perf_evsel *evsel = zalloc(sizeof(*evsel)); + struct perf_evsel *evsel = zalloc(perf_evsel__object.size); if (evsel != NULL) { struct perf_event_attr attr = { @@ -692,7 +725,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) } } -int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) +static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) { int cpu, thread; @@ -780,13 +813,13 @@ int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) return evsel->counts != NULL ? 0 : -ENOMEM; } -void perf_evsel__free_fd(struct perf_evsel *evsel) +static void perf_evsel__free_fd(struct perf_evsel *evsel) { xyarray__delete(evsel->fd); evsel->fd = NULL; } -void perf_evsel__free_id(struct perf_evsel *evsel) +static void perf_evsel__free_id(struct perf_evsel *evsel) { xyarray__delete(evsel->sample_id); evsel->sample_id = NULL; @@ -817,6 +850,7 @@ void perf_evsel__exit(struct perf_evsel *evsel) assert(list_empty(&evsel->node)); perf_evsel__free_fd(evsel); perf_evsel__free_id(evsel); + perf_evsel__object.fini(evsel); } void perf_evsel__delete(struct perf_evsel *evsel) diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 7bc314be6a7b..1d5c754aebc4 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -8,7 +8,6 @@ #include <linux/types.h> #include "xyarray.h" #include "cgroup.h" -#include "hist.h" #include "symbol.h" struct perf_counts_values { @@ -66,7 +65,6 @@ struct perf_evsel { struct perf_counts *prev_raw_counts; int idx; u32 ids; - struct hists hists; char *name; double scale; const char *unit; @@ -100,13 +98,16 @@ union u64_swap { u32 val32[2]; }; -#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists) - struct cpu_map; +struct target; struct thread_map; struct perf_evlist; struct record_opts; +int perf_evsel__object_config(size_t object_size, + int (*init)(struct perf_evsel *evsel), + void (*fini)(struct perf_evsel *evsel)); + struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) @@ -153,12 +154,9 @@ const char *perf_evsel__name(struct perf_evsel *evsel); const char *perf_evsel__group_name(struct perf_evsel *evsel); int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); -int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); -void perf_evsel__free_fd(struct perf_evsel *evsel); -void perf_evsel__free_id(struct perf_evsel *evsel); void perf_evsel__free_counts(struct perf_evsel *evsel); void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); @@ -281,8 +279,6 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel, return __perf_evsel__read(evsel, ncpus, nthreads, true); } -void hists__init(struct hists *hists); - int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, struct perf_sample *sample); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 86569fa3651d..6e88b9e395df 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -3,6 +3,7 @@ #include "hist.h" #include "session.h" #include "sort.h" +#include "evlist.h" #include "evsel.h" #include "annotate.h" #include <math.h> @@ -14,13 +15,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists, static bool hists__filter_entry_by_symbol(struct hists *hists, struct hist_entry *he); -struct callchain_param callchain_param = { - .mode = CHAIN_GRAPH_REL, - .min_percent = 0.5, - .order = ORDER_CALLEE, - .key = CCKEY_FUNCTION -}; - u16 hists__col_len(struct hists *hists, enum hist_column col) { return hists->col_len[col]; @@ -516,6 +510,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al { u64 cost; struct mem_info *mi = iter->priv; + struct hists *hists = evsel__hists(iter->evsel); struct hist_entry *he; if (mi == NULL) @@ -532,7 +527,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al * and this is indirectly achieved by passing period=weight here * and the he_stat__add_period() function. */ - he = __hists__add_entry(&iter->evsel->hists, al, iter->parent, NULL, mi, + he = __hists__add_entry(hists, al, iter->parent, NULL, mi, cost, cost, 0, true); if (!he) return -ENOMEM; @@ -546,13 +541,14 @@ iter_finish_mem_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { struct perf_evsel *evsel = iter->evsel; + struct hists *hists = evsel__hists(evsel); struct hist_entry *he = iter->he; int err = -EINVAL; if (he == NULL) goto out; - hists__inc_nr_samples(&evsel->hists, he->filtered); + hists__inc_nr_samples(hists, he->filtered); err = hist_entry__append_callchain(he, iter->sample); @@ -618,6 +614,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a { struct branch_info *bi; struct perf_evsel *evsel = iter->evsel; + struct hists *hists = evsel__hists(evsel); struct hist_entry *he = NULL; int i = iter->curr; int err = 0; @@ -631,12 +628,12 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a * The report shows the percentage of total branches captured * and not events sampled. Thus we use a pseudo period of 1. */ - he = __hists__add_entry(&evsel->hists, al, iter->parent, &bi[i], NULL, + he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, 1, 1, 0, true); if (he == NULL) return -ENOMEM; - hists__inc_nr_samples(&evsel->hists, he->filtered); + hists__inc_nr_samples(hists, he->filtered); out: iter->he = he; @@ -668,7 +665,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location struct perf_sample *sample = iter->sample; struct hist_entry *he; - he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, + he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, sample->period, sample->weight, sample->transaction, true); if (he == NULL) @@ -691,7 +688,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, iter->he = NULL; - hists__inc_nr_samples(&evsel->hists, he->filtered); + hists__inc_nr_samples(evsel__hists(evsel), he->filtered); return hist_entry__append_callchain(he, sample); } @@ -724,12 +721,13 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al) { struct perf_evsel *evsel = iter->evsel; + struct hists *hists = evsel__hists(evsel); struct perf_sample *sample = iter->sample; struct hist_entry **he_cache = iter->priv; struct hist_entry *he; int err = 0; - he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, + he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, sample->period, sample->weight, sample->transaction, true); if (he == NULL) @@ -746,7 +744,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, */ callchain_cursor_commit(&callchain_cursor); - hists__inc_nr_samples(&evsel->hists, he->filtered); + hists__inc_nr_samples(hists, he->filtered); return err; } @@ -802,7 +800,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, } } - he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, + he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, sample->period, sample->weight, sample->transaction, false); if (he == NULL) @@ -1408,6 +1406,21 @@ int hists__link(struct hists *leader, struct hists *other) return 0; } + +size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp) +{ + struct perf_evsel *pos; + size_t ret = 0; + + evlist__for_each(evlist, pos) { + ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); + ret += events_stats__fprintf(&evsel__hists(pos)->stats, fp); + } + + return ret; +} + + u64 hists__total_period(struct hists *hists) { return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period : @@ -1434,3 +1447,31 @@ int perf_hist_config(const char *var, const char *value) return 0; } + +static int hists_evsel__init(struct perf_evsel *evsel) +{ + struct hists *hists = evsel__hists(evsel); + + memset(hists, 0, sizeof(*hists)); + hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; + hists->entries_in = &hists->entries_in_array[0]; + hists->entries_collapsed = RB_ROOT; + hists->entries = RB_ROOT; + pthread_mutex_init(&hists->lock, NULL); + return 0; +} + +/* + * XXX We probably need a hists_evsel__exit() to free the hist_entries + * stored in the rbtree... + */ + +int hists__init(void) +{ + int err = perf_evsel__object_config(sizeof(struct hists_evsel), + hists_evsel__init, NULL); + if (err) + fputs("FATAL ERROR: Couldn't setup hists class\n", stderr); + + return err; +} diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 8c9c70e18cbb..d0ef9a19a744 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -4,12 +4,11 @@ #include <linux/types.h> #include <pthread.h> #include "callchain.h" +#include "evsel.h" #include "header.h" #include "color.h" #include "ui/progress.h" -extern struct callchain_param callchain_param; - struct hist_entry; struct addr_location; struct symbol; @@ -23,32 +22,6 @@ enum hist_filter { HIST_FILTER__HOST, }; -/* - * The kernel collects the number of events it couldn't send in a stretch and - * when possible sends this number in a PERF_RECORD_LOST event. The number of - * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while - * total_lost tells exactly how many events the kernel in fact lost, i.e. it is - * the sum of all struct lost_event.lost fields reported. - * - * The total_period is needed because by default auto-freq is used, so - * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get - * the total number of low level events, it is necessary to to sum all struct - * sample_event.period and stash the result in total_period. - */ -struct events_stats { - u64 total_period; - u64 total_non_filtered_period; - u64 total_lost; - u64 total_invalid_chains; - u32 nr_events[PERF_RECORD_HEADER_MAX]; - u32 nr_non_filtered_samples; - u32 nr_lost_warned; - u32 nr_unknown_events; - u32 nr_invalid_chains; - u32 nr_unknown_id; - u32 nr_unprocessable_samples; -}; - enum hist_column { HISTC_SYMBOL, HISTC_DSO, @@ -165,6 +138,7 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp); +size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); void hists__filter_by_dso(struct hists *hists); void hists__filter_by_thread(struct hists *hists); @@ -185,6 +159,25 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he); void hists__match(struct hists *leader, struct hists *other); int hists__link(struct hists *leader, struct hists *other); +struct hists_evsel { + struct perf_evsel evsel; + struct hists hists; +}; + +static inline struct perf_evsel *hists_to_evsel(struct hists *hists) +{ + struct hists_evsel *hevsel = container_of(hists, struct hists_evsel, hists); + return &hevsel->evsel; +} + +static inline struct hists *evsel__hists(struct perf_evsel *evsel) +{ + struct hists_evsel *hevsel = (struct hists_evsel *)evsel; + return &hevsel->hists; +} + +int hists__init(void); + struct perf_hpp { char *buf; size_t size; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index b7d477fbda02..34fc7c8672e4 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -13,12 +13,18 @@ #include <symbol/kallsyms.h> #include "unwind.h" +static void dsos__init(struct dsos *dsos) +{ + INIT_LIST_HEAD(&dsos->head); + dsos->root = RB_ROOT; +} + int machine__init(struct machine *machine, const char *root_dir, pid_t pid) { map_groups__init(&machine->kmaps); RB_CLEAR_NODE(&machine->rb_node); - INIT_LIST_HEAD(&machine->user_dsos.head); - INIT_LIST_HEAD(&machine->kernel_dsos.head); + dsos__init(&machine->user_dsos); + dsos__init(&machine->kernel_dsos); machine->threads = RB_ROOT; INIT_LIST_HEAD(&machine->dead_threads); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index b7090596ac50..2137c4596ec7 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -556,7 +556,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) { - if (ams->addr < ams->map->start || ams->addr > ams->map->end) { + if (ams->addr < ams->map->start || ams->addr >= ams->map->end) { if (ams->map->groups == NULL) return -1; ams->map = map_groups__find(ams->map->groups, ams->map->type, @@ -664,7 +664,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, goto move_map; } - before->end = map->start - 1; + before->end = map->start; map_groups__insert(mg, before); if (verbose >= 2) map__fprintf(before, fp); @@ -678,7 +678,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, goto move_map; } - after->start = map->end + 1; + after->start = map->end; map_groups__insert(mg, after); if (verbose >= 2) map__fprintf(after, fp); @@ -752,7 +752,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip) m = rb_entry(parent, struct map, rb_node); if (ip < m->start) p = &(*p)->rb_left; - else if (ip > m->end) + else if (ip >= m->end) p = &(*p)->rb_right; else return m; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 56ba07cce549..496f21cadd97 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -28,6 +28,7 @@ #include "../../perf.h" #include "../debug.h" +#include "../callchain.h" #include "../evsel.h" #include "../util.h" #include "../event.h" diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 883406f4b381..896bac73ea08 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -813,22 +813,6 @@ int perf_session__deliver_event(struct perf_session *session, dump_event(session, event, file_offset, sample); evsel = perf_evlist__id2evsel(session->evlist, sample->id); - if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) { - /* - * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here - * because the tools right now may apply filters, discarding - * some of the samples. For consistency, in the future we - * should have something like nr_filtered_samples and remove - * the sample->period from total_sample_period, etc, KISS for - * now tho. - * - * Also testing against NULL allows us to handle files without - * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the - * future probably it'll be a good idea to restrict event - * processing via perf_session to files with both set. - */ - hists__inc_nr_events(&evsel->hists, event->header.type); - } machine = perf_session__find_machine_for_cpumode(session, event, sample); @@ -1391,16 +1375,9 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) { - struct perf_evsel *pos; size_t ret = fprintf(fp, "Aggregated stats:\n"); ret += events_stats__fprintf(&session->stats, fp); - - evlist__for_each(session->evlist, pos) { - ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); - ret += events_stats__fprintf(&pos->hists.stats, fp); - } - return ret; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index ffb440462008..a4be851f1a90 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -2,7 +2,6 @@ #define __PERF_SESSION_H #include "trace-event.h" -#include "hist.h" #include "event.h" #include "header.h" #include "machine.h" diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 289df9d1e65a..4906cd81cb56 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1218,7 +1218,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, hse = container_of(fmt, struct hpp_sort_entry, hpp); if (!len) - len = hists__col_len(&evsel->hists, hse->se->se_width_idx); + len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); } @@ -1233,7 +1233,7 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt, hse = container_of(fmt, struct hpp_sort_entry, hpp); if (!len) - len = hists__col_len(&evsel->hists, hse->se->se_width_idx); + len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); return len; } diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index be84f7a9838b..078331140d8c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -186,7 +186,7 @@ void symbols__fixup_end(struct rb_root *symbols) curr = rb_entry(nd, struct symbol, rb_node); if (prev->end == prev->start && prev->end != curr->start) - prev->end = curr->start - 1; + prev->end = curr->start; } /* Last entry */ @@ -207,7 +207,7 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { prev = curr; curr = rb_entry(nd, struct map, rb_node); - prev->end = curr->start - 1; + prev->end = curr->start; } /* @@ -229,7 +229,7 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) sym = ((void *)sym) + symbol_conf.priv_size; sym->start = start; - sym->end = len ? start + len - 1 : start; + sym->end = len ? start + len : start; sym->binding = binding; sym->namelen = namelen - 1; @@ -325,7 +325,7 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) if (ip < s->start) n = n->rb_left; - else if (ip > s->end) + else if (ip >= s->end) n = n->rb_right; else return s; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index bec4b7bd09de..eb2c19bf8d90 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -95,7 +95,7 @@ void symbols__delete(struct rb_root *symbols); static inline size_t symbol__size(const struct symbol *sym) { - return sym->end - sym->start + 1; + return sym->end - sym->start; } struct strlist; diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 5d3215912105..f93b9734735b 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -214,6 +214,17 @@ out_free_threads: goto out; } +struct thread_map *thread_map__new_dummy(void) +{ + struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); + + if (threads != NULL) { + threads->map[0] = -1; + threads->nr = 1; + } + return threads; +} + static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) { struct thread_map *threads = NULL, *nt; @@ -224,14 +235,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) struct strlist *slist; /* perf-stat expects threads to be generated even if tid not given */ - if (!tid_str) { - threads = malloc(sizeof(*threads) + sizeof(pid_t)); - if (threads != NULL) { - threads->map[0] = -1; - threads->nr = 1; - } - return threads; - } + if (!tid_str) + return thread_map__new_dummy(); slist = strlist__new(false, tid_str); if (!slist) diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index 0cd8b3108084..95313f43cc0f 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h @@ -9,6 +9,7 @@ struct thread_map { pid_t map[]; }; +struct thread_map *thread_map__new_dummy(void); struct thread_map *thread_map__new_by_pid(pid_t pid); struct thread_map *thread_map__new_by_tid(pid_t tid); struct thread_map *thread_map__new_by_uid(uid_t uid); diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 24e8d871b74e..d5eab3f3323f 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -14,6 +14,14 @@ #include <byteswap.h> #include <linux/kernel.h> #include <unistd.h> +#include "callchain.h" + +struct callchain_param callchain_param = { + .mode = CHAIN_GRAPH_REL, + .min_percent = 0.5, + .order = ORDER_CALLEE, + .key = CCKEY_FUNCTION +}; /* * XXX We need to find a better place for these things... |