Commit ec4212d8 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 77654908 2c241bd3
...@@ -51,6 +51,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, ...@@ -51,6 +51,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
struct addr_location *al, struct addr_location *al,
struct perf_annotate *ann) struct perf_annotate *ann)
{ {
struct hists *hists = evsel__hists(evsel);
struct hist_entry *he; struct hist_entry *he;
int ret; int ret;
...@@ -66,13 +67,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, ...@@ -66,13 +67,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
return 0; return 0;
} }
he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0, he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true);
true);
if (he == NULL) if (he == NULL)
return -ENOMEM; return -ENOMEM;
ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 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; return ret;
} }
...@@ -214,6 +214,7 @@ static int __cmd_annotate(struct perf_annotate *ann) ...@@ -214,6 +214,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
if (dump_trace) { if (dump_trace) {
perf_session__fprintf_nr_events(session, stdout); perf_session__fprintf_nr_events(session, stdout);
perf_evlist__fprintf_nr_events(session->evlist, stdout);
goto out; goto out;
} }
...@@ -225,7 +226,7 @@ static int __cmd_annotate(struct perf_annotate *ann) ...@@ -225,7 +226,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
total_nr_samples = 0; total_nr_samples = 0;
evlist__for_each(session->evlist, pos) { 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]; u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
if (nr_samples > 0) { if (nr_samples > 0) {
...@@ -325,7 +326,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -325,7 +326,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
"Show event group information together"), "Show event group information together"),
OPT_END() OPT_END()
}; };
int ret; int ret = hists__init();
if (ret < 0)
return ret;
argc = parse_options(argc, argv, options, annotate_usage, 0); argc = parse_options(argc, argv, options, annotate_usage, 0);
......
...@@ -327,6 +327,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -327,6 +327,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
struct machine *machine) struct machine *machine)
{ {
struct addr_location al; struct addr_location al;
struct hists *hists = evsel__hists(evsel);
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
pr_warning("problem processing %d event, skipping it.\n", 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, ...@@ -334,7 +335,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
return -1; return -1;
} }
if (hists__add_entry(&evsel->hists, &al, sample->period, if (hists__add_entry(hists, &al, sample->period,
sample->weight, sample->transaction)) { sample->weight, sample->transaction)) {
pr_warning("problem incrementing symbol period, skipping event\n"); pr_warning("problem incrementing symbol period, skipping event\n");
return -1; return -1;
...@@ -346,9 +347,9 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -346,9 +347,9 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
* hists__output_resort() and precompute needs the total * hists__output_resort() and precompute needs the total
* period in order to sort entries by percentage delta. * 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) if (!al.filtered)
evsel->hists.stats.total_non_filtered_period += sample->period; hists->stats.total_non_filtered_period += sample->period;
return 0; return 0;
} }
...@@ -382,7 +383,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) ...@@ -382,7 +383,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
struct perf_evsel *evsel; struct perf_evsel *evsel;
evlist__for_each(evlist, evsel) { evlist__for_each(evlist, evsel) {
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
hists__collapse_resort(hists, NULL); hists__collapse_resort(hists, NULL);
} }
...@@ -631,24 +632,26 @@ static void data_process(void) ...@@ -631,24 +632,26 @@ static void data_process(void)
bool first = true; bool first = true;
evlist__for_each(evlist_base, evsel_base) { evlist__for_each(evlist_base, evsel_base) {
struct hists *hists_base = evsel__hists(evsel_base);
struct data__file *d; struct data__file *d;
int i; int i;
data__for_each_file_new(i, d) { data__for_each_file_new(i, d) {
struct perf_evlist *evlist = d->session->evlist; struct perf_evlist *evlist = d->session->evlist;
struct perf_evsel *evsel; struct perf_evsel *evsel;
struct hists *hists;
evsel = evsel_match(evsel_base, evlist); evsel = evsel_match(evsel_base, evlist);
if (!evsel) if (!evsel)
continue; 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) if (!show_baseline_only)
hists__link(&evsel_base->hists, hists__link(hists_base, hists);
&evsel->hists);
} }
fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
...@@ -659,7 +662,7 @@ static void data_process(void) ...@@ -659,7 +662,7 @@ static void data_process(void)
if (verbose || data__files_cnt > 2) if (verbose || data__files_cnt > 2)
data__fprintf(); data__fprintf();
hists__process(&evsel_base->hists); hists__process(hists_base);
} }
} }
......
...@@ -896,8 +896,7 @@ static int perf_kvm__handle_stdin(void) ...@@ -896,8 +896,7 @@ static int perf_kvm__handle_stdin(void)
static int kvm_events_live_report(struct perf_kvm_stat *kvm) static int kvm_events_live_report(struct perf_kvm_stat *kvm)
{ {
struct pollfd *pollfds = NULL; int nr_stdin, ret, err = -EINVAL;
int nr_fds, nr_stdin, ret, err = -EINVAL;
struct termios save; struct termios save;
/* live flag must be set first */ /* live flag must be set first */
...@@ -919,34 +918,27 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) ...@@ -919,34 +918,27 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
/* use pollfds -- need to add timerfd and stdin */
nr_fds = kvm->evlist->pollfd.nr;
/* add timer fd */ /* add timer fd */
if (perf_kvm__timerfd_create(kvm) < 0) { if (perf_kvm__timerfd_create(kvm) < 0) {
err = -1; err = -1;
goto out; goto out;
} }
if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd)) if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0)
goto out; goto out;
nr_fds++; nr_stdin = perf_evlist__add_pollfd(kvm->evlist, fileno(stdin));
if (nr_stdin < 0)
if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)))
goto out; goto out;
nr_stdin = nr_fds;
nr_fds++;
if (fd_set_nonblock(fileno(stdin)) != 0) if (fd_set_nonblock(fileno(stdin)) != 0)
goto out; goto out;
pollfds = kvm->evlist->pollfd.entries;
/* everything is good - enable the events and process */ /* everything is good - enable the events and process */
perf_evlist__enable(kvm->evlist); perf_evlist__enable(kvm->evlist);
while (!done) { while (!done) {
struct fdarray *fda = &kvm->evlist->pollfd;
int rc; int rc;
rc = perf_kvm__mmap_read(kvm); rc = perf_kvm__mmap_read(kvm);
...@@ -957,11 +949,11 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) ...@@ -957,11 +949,11 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
if (err) if (err)
goto out; goto out;
if (pollfds[nr_stdin].revents & POLLIN) if (fda->entries[nr_stdin].revents & POLLIN)
done = perf_kvm__handle_stdin(); done = perf_kvm__handle_stdin();
if (!rc && !done) if (!rc && !done)
err = poll(pollfds, nr_fds, 100); err = fdarray__poll(fda, 100);
} }
perf_evlist__disable(kvm->evlist); perf_evlist__disable(kvm->evlist);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "util/parse-options.h" #include "util/parse-options.h"
#include "util/parse-events.h" #include "util/parse-events.h"
#include "util/callchain.h"
#include "util/header.h" #include "util/header.h"
#include "util/event.h" #include "util/event.h"
#include "util/evlist.h" #include "util/evlist.h"
......
...@@ -288,12 +288,14 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report ...@@ -288,12 +288,14 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
evname = buf; evname = buf;
for_each_group_member(pos, evsel) { for_each_group_member(pos, evsel) {
const struct hists *pos_hists = evsel__hists(pos);
if (symbol_conf.filter_relative) { if (symbol_conf.filter_relative) {
nr_samples += pos->hists.stats.nr_non_filtered_samples; nr_samples += pos_hists->stats.nr_non_filtered_samples;
nr_events += pos->hists.stats.total_non_filtered_period; nr_events += pos_hists->stats.total_non_filtered_period;
} else { } else {
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
nr_events += pos->hists.stats.total_period; nr_events += pos_hists->stats.total_period;
} }
} }
} }
...@@ -318,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, ...@@ -318,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
struct perf_evsel *pos; struct perf_evsel *pos;
evlist__for_each(evlist, pos) { evlist__for_each(evlist, pos) {
struct hists *hists = &pos->hists; struct hists *hists = evsel__hists(pos);
const char *evname = perf_evsel__name(pos); const char *evname = perf_evsel__name(pos);
if (symbol_conf.event_group && if (symbol_conf.event_group &&
...@@ -427,7 +429,7 @@ static void report__collapse_hists(struct report *rep) ...@@ -427,7 +429,7 @@ static void report__collapse_hists(struct report *rep)
ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
evlist__for_each(rep->session->evlist, pos) { evlist__for_each(rep->session->evlist, pos) {
struct hists *hists = &pos->hists; struct hists *hists = evsel__hists(pos);
if (pos->idx == 0) if (pos->idx == 0)
hists->symbol_filter_str = rep->symbol_filter_str; hists->symbol_filter_str = rep->symbol_filter_str;
...@@ -437,7 +439,7 @@ static void report__collapse_hists(struct report *rep) ...@@ -437,7 +439,7 @@ static void report__collapse_hists(struct report *rep)
/* Non-group events are considered as leader */ /* Non-group events are considered as leader */
if (symbol_conf.event_group && if (symbol_conf.event_group &&
!perf_evsel__is_group_leader(pos)) { !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__match(leader_hists, hists);
hists__link(leader_hists, hists); hists__link(leader_hists, hists);
...@@ -485,6 +487,7 @@ static int __cmd_report(struct report *rep) ...@@ -485,6 +487,7 @@ static int __cmd_report(struct report *rep)
if (dump_trace) { if (dump_trace) {
perf_session__fprintf_nr_events(session, stdout); perf_session__fprintf_nr_events(session, stdout);
perf_evlist__fprintf_nr_events(session->evlist, stdout);
return 0; return 0;
} }
} }
...@@ -500,7 +503,7 @@ static int __cmd_report(struct report *rep) ...@@ -500,7 +503,7 @@ static int __cmd_report(struct report *rep)
} }
evlist__for_each(session->evlist, pos) evlist__for_each(session->evlist, pos)
hists__output_resort(&pos->hists); hists__output_resort(evsel__hists(pos));
return report__browse_hists(rep); return report__browse_hists(rep);
} }
...@@ -565,7 +568,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -565,7 +568,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
struct stat st; struct stat st;
bool has_br_stack = false; bool has_br_stack = false;
int branch_mode = -1; int branch_mode = -1;
int ret = -1;
char callchain_default_opt[] = "fractal,0.5,callee"; char callchain_default_opt[] = "fractal,0.5,callee";
const char * const report_usage[] = { const char * const report_usage[] = {
"perf report [<options>]", "perf report [<options>]",
...@@ -692,6 +694,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -692,6 +694,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
struct perf_data_file file = { struct perf_data_file file = {
.mode = PERF_DATA_MODE_READ, .mode = PERF_DATA_MODE_READ,
}; };
int ret = hists__init();
if (ret < 0)
return ret;
perf_config(report__config, &report); perf_config(report__config, &report);
......
...@@ -1431,9 +1431,6 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ ...@@ -1431,9 +1431,6 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
{ {
int err = 0; int err = 0;
evsel->hists.stats.total_period += sample->period;
hists__inc_nr_samples(&evsel->hists, true);
if (evsel->handler != NULL) { if (evsel->handler != NULL) {
tracepoint_handler f = evsel->handler; tracepoint_handler f = evsel->handler;
err = f(tool, evsel, sample, machine); err = f(tool, evsel, sample, machine);
......
...@@ -572,7 +572,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -572,7 +572,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
scripting_ops->process_event(event, sample, evsel, thread, &al); scripting_ops->process_event(event, sample, evsel, thread, &al);
evsel->hists.stats.total_period += sample->period;
return 0; return 0;
} }
......
...@@ -251,6 +251,7 @@ static void perf_top__print_sym_table(struct perf_top *top) ...@@ -251,6 +251,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
char bf[160]; char bf[160];
int printed = 0; int printed = 0;
const int win_width = top->winsize.ws_col - 1; const int win_width = top->winsize.ws_col - 1;
struct hists *hists = evsel__hists(top->sym_evsel);
puts(CONSOLE_CLEAR); puts(CONSOLE_CLEAR);
...@@ -261,13 +262,13 @@ static void perf_top__print_sym_table(struct perf_top *top) ...@@ -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); printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
if (top->sym_evsel->hists.stats.nr_lost_warned != if (hists->stats.nr_lost_warned !=
top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { hists->stats.nr_events[PERF_RECORD_LOST]) {
top->sym_evsel->hists.stats.nr_lost_warned = hists->stats.nr_lost_warned =
top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; hists->stats.nr_events[PERF_RECORD_LOST];
color_fprintf(stdout, PERF_COLOR_RED, color_fprintf(stdout, PERF_COLOR_RED,
"WARNING: LOST %d chunks, Check IO/CPU overload", "WARNING: LOST %d chunks, Check IO/CPU overload",
top->sym_evsel->hists.stats.nr_lost_warned); hists->stats.nr_lost_warned);
++printed; ++printed;
} }
...@@ -277,21 +278,18 @@ static void perf_top__print_sym_table(struct perf_top *top) ...@@ -277,21 +278,18 @@ static void perf_top__print_sym_table(struct perf_top *top)
} }
if (top->zero) { if (top->zero) {
hists__delete_entries(&top->sym_evsel->hists); hists__delete_entries(hists);
} else { } else {
hists__decay_entries(&top->sym_evsel->hists, hists__decay_entries(hists, top->hide_user_symbols,
top->hide_user_symbols,
top->hide_kernel_symbols); top->hide_kernel_symbols);
} }
hists__collapse_resort(&top->sym_evsel->hists, NULL); hists__collapse_resort(hists, NULL);
hists__output_resort(&top->sym_evsel->hists); hists__output_resort(hists);
hists__output_recalc_col_len(&top->sym_evsel->hists, hists__output_recalc_col_len(hists, top->print_entries - printed);
top->print_entries - printed);
putchar('\n'); putchar('\n');
hists__fprintf(&top->sym_evsel->hists, false, hists__fprintf(hists, false, top->print_entries - printed, win_width,
top->print_entries - printed, win_width,
top->min_percent, stdout); top->min_percent, stdout);
} }
...@@ -334,6 +332,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) ...@@ -334,6 +332,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
{ {
char *buf = malloc(0), *p; char *buf = malloc(0), *p;
struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
struct hists *hists = evsel__hists(top->sym_evsel);
struct rb_node *next; struct rb_node *next;
size_t dummy = 0; size_t dummy = 0;
...@@ -351,7 +350,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) ...@@ -351,7 +350,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
if (p) if (p)
*p = 0; *p = 0;
next = rb_first(&top->sym_evsel->hists.entries); next = rb_first(&hists->entries);
while (next) { while (next) {
n = rb_entry(next, struct hist_entry, rb_node); n = rb_entry(next, struct hist_entry, rb_node);
if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { 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) ...@@ -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) static void perf_top__sort_new_samples(void *arg)
{ {
struct perf_top *t = arg; struct perf_top *t = arg;
struct hists *hists;
perf_top__reset_sample_counters(t); perf_top__reset_sample_counters(t);
if (t->evlist->selected != NULL) if (t->evlist->selected != NULL)
t->sym_evsel = t->evlist->selected; t->sym_evsel = t->evlist->selected;
hists = evsel__hists(t->sym_evsel);
if (t->zero) { if (t->zero) {
hists__delete_entries(&t->sym_evsel->hists); hists__delete_entries(hists);
} else { } else {
hists__decay_entries(&t->sym_evsel->hists, hists__decay_entries(hists, t->hide_user_symbols,
t->hide_user_symbols,
t->hide_kernel_symbols); t->hide_kernel_symbols);
} }
hists__collapse_resort(&t->sym_evsel->hists, NULL); hists__collapse_resort(hists, NULL);
hists__output_resort(&t->sym_evsel->hists); hists__output_resort(hists);
} }
static void *display_thread_tui(void *arg) static void *display_thread_tui(void *arg)
...@@ -573,8 +575,10 @@ 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 * Zooming in/out UIDs. For now juse use whatever the user passed
* via --uid. * via --uid.
*/ */
evlist__for_each(top->evlist, pos) evlist__for_each(top->evlist, pos) {
pos->hists.uid_filter_str = top->record_opts.target.uid_str; 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, perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
&top->session->header.env); &top->session->header.env);
...@@ -768,6 +772,7 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -768,6 +772,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
} }
if (al.sym == NULL || !al.sym->ignore) { if (al.sym == NULL || !al.sym->ignore) {
struct hists *hists = evsel__hists(evsel);
struct hist_entry_iter iter = { struct hist_entry_iter iter = {
.add_entry_cb = hist_iter__top_callback, .add_entry_cb = hist_iter__top_callback,
}; };
...@@ -777,14 +782,14 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -777,14 +782,14 @@ static void perf_event__process_sample(struct perf_tool *tool,
else else
iter.ops = &hist_iter_normal; 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, err = hist_entry_iter__add(&iter, &al, evsel, sample,
top->max_stack, top); top->max_stack, top);
if (err < 0) if (err < 0)
pr_err("Problem incrementing symbol period, skipping event\n"); pr_err("Problem incrementing symbol period, skipping event\n");
pthread_mutex_unlock(&evsel->hists.lock); pthread_mutex_unlock(&hists->lock);
} }
return; return;
...@@ -849,7 +854,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) ...@@ -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, perf_event__process_sample(&top->tool, event, evsel,
&sample, machine); &sample, machine);
} else if (event->header.type < PERF_RECORD_MAX) { } 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); machine__process_event(machine, event, &sample);
} else } else
++session->stats.nr_unknown_events; ++session->stats.nr_unknown_events;
...@@ -1042,7 +1047,6 @@ parse_percent_limit(const struct option *opt, const char *arg, ...@@ -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 cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
int status = -1;
char errbuf[BUFSIZ]; char errbuf[BUFSIZ];
struct perf_top top = { struct perf_top top = {
.count_filter = 5, .count_filter = 5,
...@@ -1160,6 +1164,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1160,6 +1164,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
"perf top [<options>]", "perf top [<options>]",
NULL NULL
}; };
int status = hists__init();
if (status < 0)
return status;
top.evlist = perf_evlist__new(); top.evlist = perf_evlist__new();
if (top.evlist == NULL) if (top.evlist == NULL)
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include "builtin.h" #include "builtin.h"
#include "hist.h"
#include "intlist.h" #include "intlist.h"
#include "tests.h" #include "tests.h"
#include "debug.h" #include "debug.h"
...@@ -302,6 +303,10 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -302,6 +303,10 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_END() OPT_END()
}; };
struct intlist *skiplist = NULL; struct intlist *skiplist = NULL;
int ret = hists__init();
if (ret < 0)
return ret;
argc = parse_options(argc, argv, test_options, test_usage, 0); argc = parse_options(argc, argv, test_options, test_usage, 0);
if (argc >= 1 && !strcmp(argv[0], "list")) if (argc >= 1 && !strcmp(argv[0], "list"))
......
...@@ -245,7 +245,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec ...@@ -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) static int test1(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
/* /*
* expected output: * expected output:
* *
...@@ -295,7 +295,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine) ...@@ -295,7 +295,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
static int test2(struct perf_evsel *evsel, struct machine *machine) static int test2(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
/* /*
* expected output: * expected output:
* *
...@@ -442,7 +442,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine) ...@@ -442,7 +442,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
static int test3(struct perf_evsel *evsel, struct machine *machine) static int test3(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
/* /*
* expected output: * expected output:
* *
...@@ -498,7 +498,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) ...@@ -498,7 +498,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
static int test4(struct perf_evsel *evsel, struct machine *machine) static int test4(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
/* /*
* expected output: * expected output:
* *
......
...@@ -66,11 +66,12 @@ static int add_hist_entries(struct perf_evlist *evlist, ...@@ -66,11 +66,12 @@ static int add_hist_entries(struct perf_evlist *evlist,
.ops = &hist_iter_normal, .ops = &hist_iter_normal,
.hide_unresolved = false, .hide_unresolved = false,
}; };
struct hists *hists = evsel__hists(evsel);
/* make sure it has no filter at first */ /* make sure it has no filter at first */
evsel->hists.thread_filter = NULL; hists->thread_filter = NULL;
evsel->hists.dso_filter = NULL; hists->dso_filter = NULL;
evsel->hists.symbol_filter_str = NULL; hists->symbol_filter_str = NULL;
sample.pid = fake_samples[i].pid; sample.pid = fake_samples[i].pid;
sample.tid = fake_samples[i].pid; sample.tid = fake_samples[i].pid;
...@@ -134,7 +135,7 @@ int test__hists_filter(void) ...@@ -134,7 +135,7 @@ int test__hists_filter(void)
goto out; goto out;
evlist__for_each(evlist, evsel) { evlist__for_each(evlist, evsel) {
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
hists__collapse_resort(hists, NULL); hists__collapse_resort(hists, NULL);
hists__output_resort(hists); hists__output_resort(hists);
...@@ -160,7 +161,7 @@ int test__hists_filter(void) ...@@ -160,7 +161,7 @@ int test__hists_filter(void)
hists->stats.total_non_filtered_period); hists->stats.total_non_filtered_period);
/* now applying thread filter for 'bash' */ /* 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); hists__filter_by_thread(hists);
if (verbose > 2) { if (verbose > 2) {
...@@ -185,11 +186,11 @@ int test__hists_filter(void) ...@@ -185,11 +186,11 @@ int test__hists_filter(void)
hists->stats.total_non_filtered_period == 400); hists->stats.total_non_filtered_period == 400);
/* remove thread filter first */ /* remove thread filter first */
evsel->hists.thread_filter = NULL; hists->thread_filter = NULL;
hists__filter_by_thread(hists); hists__filter_by_thread(hists);
/* now applying dso filter for 'kernel' */ /* 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); hists__filter_by_dso(hists);
if (verbose > 2) { if (verbose > 2) {
...@@ -214,7 +215,7 @@ int test__hists_filter(void) ...@@ -214,7 +215,7 @@ int test__hists_filter(void)
hists->stats.total_non_filtered_period == 300); hists->stats.total_non_filtered_period == 300);
/* remove dso filter first */ /* remove dso filter first */
evsel->hists.dso_filter = NULL; hists->dso_filter = NULL;
hists__filter_by_dso(hists); hists__filter_by_dso(hists);
/* /*
...@@ -224,7 +225,7 @@ int test__hists_filter(void) ...@@ -224,7 +225,7 @@ int test__hists_filter(void)
* be counted as a separate entry but the sample count and * be counted as a separate entry but the sample count and
* total period will be remained. * total period will be remained.
*/ */
evsel->hists.symbol_filter_str = "main"; hists->symbol_filter_str = "main";
hists__filter_by_symbol(hists); hists__filter_by_symbol(hists);
if (verbose > 2) { if (verbose > 2) {
...@@ -249,8 +250,8 @@ int test__hists_filter(void) ...@@ -249,8 +250,8 @@ int test__hists_filter(void)
hists->stats.total_non_filtered_period == 300); hists->stats.total_non_filtered_period == 300);
/* now applying all filters at once. */ /* now applying all filters at once. */
evsel->hists.thread_filter = fake_samples[1].thread; hists->thread_filter = fake_samples[1].thread;
evsel->hists.dso_filter = fake_samples[1].map->dso; hists->dso_filter = fake_samples[1].map->dso;
hists__filter_by_thread(hists); hists__filter_by_thread(hists);
hists__filter_by_dso(hists); hists__filter_by_dso(hists);
......
...@@ -73,6 +73,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) ...@@ -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. * "bash [libc] malloc" so total 9 entries will be in the tree.
*/ */
evlist__for_each(evlist, evsel) { evlist__for_each(evlist, evsel) {
struct hists *hists = evsel__hists(evsel);
for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
const union perf_event event = { const union perf_event event = {
.header = { .header = {
...@@ -87,7 +89,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) ...@@ -87,7 +89,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
&sample) < 0) &sample) < 0)
goto out; goto out;
he = __hists__add_entry(&evsel->hists, &al, NULL, he = __hists__add_entry(hists, &al, NULL,
NULL, NULL, 1, 1, 0, true); NULL, NULL, 1, 1, 0, true);
if (he == NULL) if (he == NULL)
goto out; goto out;
...@@ -111,7 +113,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) ...@@ -111,7 +113,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
&sample) < 0) &sample) < 0)
goto out; goto out;
he = __hists__add_entry(&evsel->hists, &al, NULL, he = __hists__add_entry(hists, &al, NULL,
NULL, NULL, 1, 1, 0, true); NULL, NULL, 1, 1, 0, true);
if (he == NULL) if (he == NULL)
goto out; goto out;
...@@ -271,6 +273,7 @@ static int validate_link(struct hists *leader, struct hists *other) ...@@ -271,6 +273,7 @@ static int validate_link(struct hists *leader, struct hists *other)
int test__hists_link(void) int test__hists_link(void)
{ {
int err = -1; int err = -1;
struct hists *hists, *first_hists;
struct machines machines; struct machines machines;
struct machine *machine = NULL; struct machine *machine = NULL;
struct perf_evsel *evsel, *first; struct perf_evsel *evsel, *first;
...@@ -306,24 +309,28 @@ int test__hists_link(void) ...@@ -306,24 +309,28 @@ int test__hists_link(void)
goto out; goto out;
evlist__for_each(evlist, evsel) { evlist__for_each(evlist, evsel) {
hists__collapse_resort(&evsel->hists, NULL); hists = evsel__hists(evsel);
hists__collapse_resort(hists, NULL);
if (verbose > 2) if (verbose > 2)
print_hists_in(&evsel->hists); print_hists_in(hists);
} }
first = perf_evlist__first(evlist); first = perf_evlist__first(evlist);
evsel = perf_evlist__last(evlist); evsel = perf_evlist__last(evlist);
first_hists = evsel__hists(first);
hists = evsel__hists(evsel);
/* match common entries */ /* match common entries */
hists__match(&first->hists, &evsel->hists); hists__match(first_hists, hists);
err = validate_match(&first->hists, &evsel->hists); err = validate_match(first_hists, hists);
if (err) if (err)
goto out; goto out;
/* link common and/or dummy entries */ /* link common and/or dummy entries */
hists__link(&first->hists, &evsel->hists); hists__link(first_hists, hists);
err = validate_link(&first->hists, &evsel->hists); err = validate_link(first_hists, hists);
if (err) if (err)
goto out; goto out;
......
...@@ -122,7 +122,7 @@ typedef int (*test_fn_t)(struct perf_evsel *, struct machine *); ...@@ -122,7 +122,7 @@ typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
static int test1(struct perf_evsel *evsel, struct machine *machine) static int test1(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
struct hist_entry *he; struct hist_entry *he;
struct rb_root *root; struct rb_root *root;
struct rb_node *node; struct rb_node *node;
...@@ -159,7 +159,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine) ...@@ -159,7 +159,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
print_hists_out(hists); print_hists_out(hists);
} }
root = &evsel->hists.entries; root = &hists->entries;
node = rb_first(root); node = rb_first(root);
he = rb_entry(node, struct hist_entry, rb_node); he = rb_entry(node, struct hist_entry, rb_node);
TEST_ASSERT_VAL("Invalid hist entry", TEST_ASSERT_VAL("Invalid hist entry",
...@@ -224,7 +224,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine) ...@@ -224,7 +224,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
static int test2(struct perf_evsel *evsel, struct machine *machine) static int test2(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
struct hist_entry *he; struct hist_entry *he;
struct rb_root *root; struct rb_root *root;
struct rb_node *node; struct rb_node *node;
...@@ -259,7 +259,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine) ...@@ -259,7 +259,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
print_hists_out(hists); print_hists_out(hists);
} }
root = &evsel->hists.entries; root = &hists->entries;
node = rb_first(root); node = rb_first(root);
he = rb_entry(node, struct hist_entry, rb_node); he = rb_entry(node, struct hist_entry, rb_node);
TEST_ASSERT_VAL("Invalid hist entry", TEST_ASSERT_VAL("Invalid hist entry",
...@@ -280,7 +280,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine) ...@@ -280,7 +280,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
static int test3(struct perf_evsel *evsel, struct machine *machine) static int test3(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
struct hist_entry *he; struct hist_entry *he;
struct rb_root *root; struct rb_root *root;
struct rb_node *node; struct rb_node *node;
...@@ -313,7 +313,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) ...@@ -313,7 +313,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
print_hists_out(hists); print_hists_out(hists);
} }
root = &evsel->hists.entries; root = &hists->entries;
node = rb_first(root); node = rb_first(root);
he = rb_entry(node, struct hist_entry, rb_node); he = rb_entry(node, struct hist_entry, rb_node);
TEST_ASSERT_VAL("Invalid hist entry", TEST_ASSERT_VAL("Invalid hist entry",
...@@ -354,7 +354,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine) ...@@ -354,7 +354,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
static int test4(struct perf_evsel *evsel, struct machine *machine) static int test4(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
struct hist_entry *he; struct hist_entry *he;
struct rb_root *root; struct rb_root *root;
struct rb_node *node; struct rb_node *node;
...@@ -391,7 +391,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) ...@@ -391,7 +391,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
print_hists_out(hists); print_hists_out(hists);
} }
root = &evsel->hists.entries; root = &hists->entries;
node = rb_first(root); node = rb_first(root);
he = rb_entry(node, struct hist_entry, rb_node); he = rb_entry(node, struct hist_entry, rb_node);
TEST_ASSERT_VAL("Invalid hist entry", TEST_ASSERT_VAL("Invalid hist entry",
...@@ -456,7 +456,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine) ...@@ -456,7 +456,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
static int test5(struct perf_evsel *evsel, struct machine *machine) static int test5(struct perf_evsel *evsel, struct machine *machine)
{ {
int err; int err;
struct hists *hists = &evsel->hists; struct hists *hists = evsel__hists(evsel);
struct hist_entry *he; struct hist_entry *he;
struct rb_root *root; struct rb_root *root;
struct rb_node *node; struct rb_node *node;
...@@ -494,7 +494,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine) ...@@ -494,7 +494,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
print_hists_out(hists); print_hists_out(hists);
} }
root = &evsel->hists.entries; root = &hists->entries;
node = rb_first(root); node = rb_first(root);
he = rb_entry(node, struct hist_entry, rb_node); he = rb_entry(node, struct hist_entry, rb_node);
......
#include "util/cache.h" #include "util/cache.h"
#include "util/debug.h" #include "util/debug.h"
#include "ui/browser.h" #include "ui/browser.h"
#include "ui/keysyms.h"
#include "ui/ui.h" #include "ui/ui.h"
#include "ui/util.h" #include "ui/util.h"
#include "ui/libslang.h" #include "ui/libslang.h"
......
...@@ -1229,12 +1229,14 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size) ...@@ -1229,12 +1229,14 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size)
ev_name = buf; ev_name = buf;
for_each_group_member(pos, evsel) { for_each_group_member(pos, evsel) {
struct hists *pos_hists = evsel__hists(pos);
if (symbol_conf.filter_relative) { if (symbol_conf.filter_relative) {
nr_samples += pos->hists.stats.nr_non_filtered_samples; nr_samples += pos_hists->stats.nr_non_filtered_samples;
nr_events += pos->hists.stats.total_non_filtered_period; nr_events += pos_hists->stats.total_non_filtered_period;
} else { } else {
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
nr_events += pos->hists.stats.total_period; nr_events += pos_hists->stats.total_period;
} }
} }
} }
...@@ -1387,7 +1389,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1387,7 +1389,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
float min_pcnt, float min_pcnt,
struct perf_session_env *env) 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 hist_browser *browser = hist_browser__new(hists);
struct branch_info *bi; struct branch_info *bi;
struct pstack *fstack; struct pstack *fstack;
...@@ -1802,8 +1804,9 @@ static void perf_evsel_menu__write(struct ui_browser *browser, ...@@ -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 *menu = container_of(browser,
struct perf_evsel_menu, b); struct perf_evsel_menu, b);
struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 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); 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); const char *ev_name = perf_evsel__name(evsel);
char bf[256], unit; char bf[256], unit;
const char *warn = " "; const char *warn = " ";
...@@ -1818,7 +1821,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser, ...@@ -1818,7 +1821,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
ev_name = perf_evsel__group_name(evsel); ev_name = perf_evsel__group_name(evsel);
for_each_group_member(pos, 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, ...@@ -1827,7 +1831,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
unit, unit == ' ' ? "" : " ", ev_name); unit, unit == ' ' ? "" : " ", ev_name);
slsmg_printf("%s", bf); 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) { if (nr_events != 0) {
menu->lost_events = true; menu->lost_events = true;
if (!current_entry) if (!current_entry)
......
...@@ -319,7 +319,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, ...@@ -319,7 +319,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
gtk_container_add(GTK_CONTAINER(window), vbox); gtk_container_add(GTK_CONTAINER(window), vbox);
evlist__for_each(evlist, pos) { evlist__for_each(evlist, pos) {
struct hists *hists = &pos->hists; struct hists *hists = evsel__hists(pos);
const char *evname = perf_evsel__name(pos); const char *evname = perf_evsel__name(pos);
GtkWidget *scrolled_window; GtkWidget *scrolled_window;
GtkWidget *tab_label; GtkWidget *tab_label;
......
...@@ -478,7 +478,7 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, ...@@ -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)); 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; return -ERANGE;
offset = addr - sym->start; offset = addr - sym->start;
...@@ -836,7 +836,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, ...@@ -836,7 +836,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
end = map__rip_2objdump(map, sym->end); end = map__rip_2objdump(map, sym->end);
offset = line_ip - start; offset = line_ip - start;
if ((u64)line_ip < start || (u64)line_ip > end) if ((u64)line_ip < start || (u64)line_ip >= end)
offset = -1; offset = -1;
else else
parsed_line = tmp2 + 1; parsed_line = tmp2 + 1;
...@@ -966,7 +966,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -966,7 +966,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
kce.kcore_filename = symfs_filename; kce.kcore_filename = symfs_filename;
kce.addr = map__rip_2objdump(map, sym->start); kce.addr = map__rip_2objdump(map, sym->start);
kce.offs = sym->start; kce.offs = sym->start;
kce.len = sym->end + 1 - sym->start; kce.len = sym->end - sym->start;
if (!kcore_extract__create(&kce)) { if (!kcore_extract__create(&kce)) {
delete_extract = true; delete_extract = true;
strlcpy(symfs_filename, kce.extract_filename, strlcpy(symfs_filename, kce.extract_filename,
...@@ -987,7 +987,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) ...@@ -987,7 +987,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
disassembler_style ? "-M " : "", disassembler_style ? "-M " : "",
disassembler_style ? disassembler_style : "", disassembler_style ? disassembler_style : "",
map__rip_2objdump(map, sym->start), 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_asm_raw ? "" : "--no-show-raw",
symbol_conf.annotate_src ? "-S" : "", symbol_conf.annotate_src ? "-S" : "",
symfs_filename, filename); symfs_filename, filename);
......
...@@ -65,6 +65,8 @@ struct callchain_param { ...@@ -65,6 +65,8 @@ struct callchain_param {
enum chain_key key; enum chain_key key;
}; };
extern struct callchain_param callchain_param;
struct callchain_list { struct callchain_list {
u64 ip; u64 ip;
struct map_symbol ms; struct map_symbol ms;
......
...@@ -190,6 +190,32 @@ enum perf_user_event_type { /* above any possible kernel type */ ...@@ -190,6 +190,32 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_HEADER_MAX 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 attr_event {
struct perf_event_header header; struct perf_event_header header;
struct perf_event_attr attr; struct perf_event_attr attr;
......
...@@ -1175,11 +1175,51 @@ void perf_evlist__close(struct perf_evlist *evlist) ...@@ -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) int perf_evlist__open(struct perf_evlist *evlist)
{ {
struct perf_evsel *evsel; struct perf_evsel *evsel;
int err; 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); perf_evlist__update_id_pos(evlist);
evlist__for_each(evlist, evsel) { evlist__for_each(evlist, evsel) {
...@@ -1276,8 +1316,14 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar ...@@ -1276,8 +1316,14 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
sigaction(SIGUSR1, &act, NULL); 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; evlist->threads->map[0] = evlist->workload.pid;
}
close(child_ready_pipe[1]); close(child_ready_pipe[1]);
close(go_pipe[0]); close(go_pipe[0]);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <sys/resource.h> #include <sys/resource.h>
#include "asm/bug.h" #include "asm/bug.h"
#include "callchain.h"
#include "evsel.h" #include "evsel.h"
#include "evlist.h" #include "evlist.h"
#include "util.h" #include "util.h"
...@@ -32,6 +33,48 @@ static struct { ...@@ -32,6 +33,48 @@ static struct {
bool cloexec; bool cloexec;
} perf_missing_features; } 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)) #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
int __perf_evsel__sample_size(u64 sample_type) int __perf_evsel__sample_size(u64 sample_type)
...@@ -116,16 +159,6 @@ void perf_evsel__calc_id_pos(struct perf_evsel *evsel) ...@@ -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); 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, void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
enum perf_event_sample_format bit) enum perf_event_sample_format bit)
{ {
...@@ -168,14 +201,14 @@ void perf_evsel__init(struct perf_evsel *evsel, ...@@ -168,14 +201,14 @@ void perf_evsel__init(struct perf_evsel *evsel,
evsel->unit = ""; evsel->unit = "";
evsel->scale = 1.0; evsel->scale = 1.0;
INIT_LIST_HEAD(&evsel->node); INIT_LIST_HEAD(&evsel->node);
hists__init(&evsel->hists); perf_evsel__object.init(evsel);
evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
perf_evsel__calc_id_pos(evsel); perf_evsel__calc_id_pos(evsel);
} }
struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) 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) if (evsel != NULL)
perf_evsel__init(evsel, attr, idx); perf_evsel__init(evsel, attr, idx);
...@@ -185,7 +218,7 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int 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 *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) { if (evsel != NULL) {
struct perf_event_attr attr = { struct perf_event_attr attr = {
...@@ -692,7 +725,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) ...@@ -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; int cpu, thread;
...@@ -780,13 +813,13 @@ int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) ...@@ -780,13 +813,13 @@ int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
return evsel->counts != NULL ? 0 : -ENOMEM; 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); xyarray__delete(evsel->fd);
evsel->fd = NULL; 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); xyarray__delete(evsel->sample_id);
evsel->sample_id = NULL; evsel->sample_id = NULL;
...@@ -817,6 +850,7 @@ void perf_evsel__exit(struct perf_evsel *evsel) ...@@ -817,6 +850,7 @@ void perf_evsel__exit(struct perf_evsel *evsel)
assert(list_empty(&evsel->node)); assert(list_empty(&evsel->node));
perf_evsel__free_fd(evsel); perf_evsel__free_fd(evsel);
perf_evsel__free_id(evsel); perf_evsel__free_id(evsel);
perf_evsel__object.fini(evsel);
} }
void perf_evsel__delete(struct perf_evsel *evsel) void perf_evsel__delete(struct perf_evsel *evsel)
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <linux/types.h> #include <linux/types.h>
#include "xyarray.h" #include "xyarray.h"
#include "cgroup.h" #include "cgroup.h"
#include "hist.h"
#include "symbol.h" #include "symbol.h"
struct perf_counts_values { struct perf_counts_values {
...@@ -66,7 +65,6 @@ struct perf_evsel { ...@@ -66,7 +65,6 @@ struct perf_evsel {
struct perf_counts *prev_raw_counts; struct perf_counts *prev_raw_counts;
int idx; int idx;
u32 ids; u32 ids;
struct hists hists;
char *name; char *name;
double scale; double scale;
const char *unit; const char *unit;
...@@ -100,13 +98,16 @@ union u64_swap { ...@@ -100,13 +98,16 @@ union u64_swap {
u32 val32[2]; u32 val32[2];
}; };
#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
struct cpu_map; struct cpu_map;
struct target;
struct thread_map; struct thread_map;
struct perf_evlist; struct perf_evlist;
struct record_opts; 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); 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) 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); ...@@ -153,12 +154,9 @@ const char *perf_evsel__name(struct perf_evsel *evsel);
const char *perf_evsel__group_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__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_id(struct perf_evsel *evsel, int ncpus, int nthreads);
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 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__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__free_counts(struct perf_evsel *evsel);
void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 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, ...@@ -281,8 +279,6 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
return __perf_evsel__read(evsel, ncpus, nthreads, true); 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, int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
struct perf_sample *sample); struct perf_sample *sample);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "hist.h" #include "hist.h"
#include "session.h" #include "session.h"
#include "sort.h" #include "sort.h"
#include "evlist.h"
#include "evsel.h" #include "evsel.h"
#include "annotate.h" #include "annotate.h"
#include <math.h> #include <math.h>
...@@ -14,13 +15,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists, ...@@ -14,13 +15,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
static bool hists__filter_entry_by_symbol(struct hists *hists, static bool hists__filter_entry_by_symbol(struct hists *hists,
struct hist_entry *he); 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) u16 hists__col_len(struct hists *hists, enum hist_column col)
{ {
return hists->col_len[col]; return hists->col_len[col];
...@@ -516,6 +510,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al ...@@ -516,6 +510,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
{ {
u64 cost; u64 cost;
struct mem_info *mi = iter->priv; struct mem_info *mi = iter->priv;
struct hists *hists = evsel__hists(iter->evsel);
struct hist_entry *he; struct hist_entry *he;
if (mi == NULL) if (mi == NULL)
...@@ -532,7 +527,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al ...@@ -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 this is indirectly achieved by passing period=weight here
* and the he_stat__add_period() function. * 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); cost, cost, 0, true);
if (!he) if (!he)
return -ENOMEM; return -ENOMEM;
...@@ -546,13 +541,14 @@ iter_finish_mem_entry(struct hist_entry_iter *iter, ...@@ -546,13 +541,14 @@ iter_finish_mem_entry(struct hist_entry_iter *iter,
struct addr_location *al __maybe_unused) struct addr_location *al __maybe_unused)
{ {
struct perf_evsel *evsel = iter->evsel; struct perf_evsel *evsel = iter->evsel;
struct hists *hists = evsel__hists(evsel);
struct hist_entry *he = iter->he; struct hist_entry *he = iter->he;
int err = -EINVAL; int err = -EINVAL;
if (he == NULL) if (he == NULL)
goto out; 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); 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 ...@@ -618,6 +614,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
{ {
struct branch_info *bi; struct branch_info *bi;
struct perf_evsel *evsel = iter->evsel; struct perf_evsel *evsel = iter->evsel;
struct hists *hists = evsel__hists(evsel);
struct hist_entry *he = NULL; struct hist_entry *he = NULL;
int i = iter->curr; int i = iter->curr;
int err = 0; int err = 0;
...@@ -631,12 +628,12 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a ...@@ -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 * The report shows the percentage of total branches captured
* and not events sampled. Thus we use a pseudo period of 1. * 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); 1, 1, 0, true);
if (he == NULL) if (he == NULL)
return -ENOMEM; return -ENOMEM;
hists__inc_nr_samples(&evsel->hists, he->filtered); hists__inc_nr_samples(hists, he->filtered);
out: out:
iter->he = he; iter->he = he;
...@@ -668,7 +665,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location ...@@ -668,7 +665,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
struct perf_sample *sample = iter->sample; struct perf_sample *sample = iter->sample;
struct hist_entry *he; 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->period, sample->weight,
sample->transaction, true); sample->transaction, true);
if (he == NULL) if (he == NULL)
...@@ -691,7 +688,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, ...@@ -691,7 +688,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter,
iter->he = NULL; 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); return hist_entry__append_callchain(he, sample);
} }
...@@ -724,12 +721,13 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, ...@@ -724,12 +721,13 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
struct addr_location *al) struct addr_location *al)
{ {
struct perf_evsel *evsel = iter->evsel; struct perf_evsel *evsel = iter->evsel;
struct hists *hists = evsel__hists(evsel);
struct perf_sample *sample = iter->sample; struct perf_sample *sample = iter->sample;
struct hist_entry **he_cache = iter->priv; struct hist_entry **he_cache = iter->priv;
struct hist_entry *he; struct hist_entry *he;
int err = 0; 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->period, sample->weight,
sample->transaction, true); sample->transaction, true);
if (he == NULL) if (he == NULL)
...@@ -746,7 +744,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter, ...@@ -746,7 +744,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
*/ */
callchain_cursor_commit(&callchain_cursor); callchain_cursor_commit(&callchain_cursor);
hists__inc_nr_samples(&evsel->hists, he->filtered); hists__inc_nr_samples(hists, he->filtered);
return err; return err;
} }
...@@ -802,7 +800,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, ...@@ -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->period, sample->weight,
sample->transaction, false); sample->transaction, false);
if (he == NULL) if (he == NULL)
...@@ -1408,6 +1406,21 @@ int hists__link(struct hists *leader, struct hists *other) ...@@ -1408,6 +1406,21 @@ int hists__link(struct hists *leader, struct hists *other)
return 0; 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) u64 hists__total_period(struct hists *hists)
{ {
return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period : 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) ...@@ -1434,3 +1447,31 @@ int perf_hist_config(const char *var, const char *value)
return 0; 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;
}
...@@ -4,12 +4,11 @@ ...@@ -4,12 +4,11 @@
#include <linux/types.h> #include <linux/types.h>
#include <pthread.h> #include <pthread.h>
#include "callchain.h" #include "callchain.h"
#include "evsel.h"
#include "header.h" #include "header.h"
#include "color.h" #include "color.h"
#include "ui/progress.h" #include "ui/progress.h"
extern struct callchain_param callchain_param;
struct hist_entry; struct hist_entry;
struct addr_location; struct addr_location;
struct symbol; struct symbol;
...@@ -23,32 +22,6 @@ enum hist_filter { ...@@ -23,32 +22,6 @@ enum hist_filter {
HIST_FILTER__HOST, 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 { enum hist_column {
HISTC_SYMBOL, HISTC_SYMBOL,
HISTC_DSO, HISTC_DSO,
...@@ -165,6 +138,7 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); ...@@ -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, size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, float min_pcnt, FILE *fp); 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_dso(struct hists *hists);
void hists__filter_by_thread(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); ...@@ -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); void hists__match(struct hists *leader, struct hists *other);
int hists__link(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 { struct perf_hpp {
char *buf; char *buf;
size_t size; size_t size;
......
...@@ -13,12 +13,18 @@ ...@@ -13,12 +13,18 @@
#include <symbol/kallsyms.h> #include <symbol/kallsyms.h>
#include "unwind.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) int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
{ {
map_groups__init(&machine->kmaps); map_groups__init(&machine->kmaps);
RB_CLEAR_NODE(&machine->rb_node); RB_CLEAR_NODE(&machine->rb_node);
INIT_LIST_HEAD(&machine->user_dsos.head); dsos__init(&machine->user_dsos);
INIT_LIST_HEAD(&machine->kernel_dsos.head); dsos__init(&machine->kernel_dsos);
machine->threads = RB_ROOT; machine->threads = RB_ROOT;
INIT_LIST_HEAD(&machine->dead_threads); INIT_LIST_HEAD(&machine->dead_threads);
......
...@@ -556,7 +556,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, ...@@ -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) 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) if (ams->map->groups == NULL)
return -1; return -1;
ams->map = map_groups__find(ams->map->groups, ams->map->type, 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, ...@@ -664,7 +664,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
goto move_map; goto move_map;
} }
before->end = map->start - 1; before->end = map->start;
map_groups__insert(mg, before); map_groups__insert(mg, before);
if (verbose >= 2) if (verbose >= 2)
map__fprintf(before, fp); map__fprintf(before, fp);
...@@ -678,7 +678,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, ...@@ -678,7 +678,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
goto move_map; goto move_map;
} }
after->start = map->end + 1; after->start = map->end;
map_groups__insert(mg, after); map_groups__insert(mg, after);
if (verbose >= 2) if (verbose >= 2)
map__fprintf(after, fp); map__fprintf(after, fp);
...@@ -752,7 +752,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip) ...@@ -752,7 +752,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
m = rb_entry(parent, struct map, rb_node); m = rb_entry(parent, struct map, rb_node);
if (ip < m->start) if (ip < m->start)
p = &(*p)->rb_left; p = &(*p)->rb_left;
else if (ip > m->end) else if (ip >= m->end)
p = &(*p)->rb_right; p = &(*p)->rb_right;
else else
return m; return m;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "../../perf.h" #include "../../perf.h"
#include "../debug.h" #include "../debug.h"
#include "../callchain.h"
#include "../evsel.h" #include "../evsel.h"
#include "../util.h" #include "../util.h"
#include "../event.h" #include "../event.h"
......
...@@ -813,22 +813,6 @@ int perf_session__deliver_event(struct perf_session *session, ...@@ -813,22 +813,6 @@ int perf_session__deliver_event(struct perf_session *session,
dump_event(session, event, file_offset, sample); dump_event(session, event, file_offset, sample);
evsel = perf_evlist__id2evsel(session->evlist, sample->id); 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, machine = perf_session__find_machine_for_cpumode(session, event,
sample); sample);
...@@ -1391,16 +1375,9 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp ...@@ -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) 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"); size_t ret = fprintf(fp, "Aggregated stats:\n");
ret += events_stats__fprintf(&session->stats, fp); 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; return ret;
} }
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#define __PERF_SESSION_H #define __PERF_SESSION_H
#include "trace-event.h" #include "trace-event.h"
#include "hist.h"
#include "event.h" #include "event.h"
#include "header.h" #include "header.h"
#include "machine.h" #include "machine.h"
......
...@@ -1218,7 +1218,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, ...@@ -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); hse = container_of(fmt, struct hpp_sort_entry, hpp);
if (!len) 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); 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, ...@@ -1233,7 +1233,7 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
hse = container_of(fmt, struct hpp_sort_entry, hpp); hse = container_of(fmt, struct hpp_sort_entry, hpp);
if (!len) 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; return len;
} }
......
...@@ -186,7 +186,7 @@ void symbols__fixup_end(struct rb_root *symbols) ...@@ -186,7 +186,7 @@ void symbols__fixup_end(struct rb_root *symbols)
curr = rb_entry(nd, struct symbol, rb_node); curr = rb_entry(nd, struct symbol, rb_node);
if (prev->end == prev->start && prev->end != curr->start) if (prev->end == prev->start && prev->end != curr->start)
prev->end = curr->start - 1; prev->end = curr->start;
} }
/* Last entry */ /* Last entry */
...@@ -207,7 +207,7 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) ...@@ -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)) { for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
prev = curr; prev = curr;
curr = rb_entry(nd, struct map, rb_node); 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) ...@@ -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 = ((void *)sym) + symbol_conf.priv_size;
sym->start = start; sym->start = start;
sym->end = len ? start + len - 1 : start; sym->end = len ? start + len : start;
sym->binding = binding; sym->binding = binding;
sym->namelen = namelen - 1; sym->namelen = namelen - 1;
...@@ -325,7 +325,7 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) ...@@ -325,7 +325,7 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
if (ip < s->start) if (ip < s->start)
n = n->rb_left; n = n->rb_left;
else if (ip > s->end) else if (ip >= s->end)
n = n->rb_right; n = n->rb_right;
else else
return s; return s;
......
...@@ -95,7 +95,7 @@ void symbols__delete(struct rb_root *symbols); ...@@ -95,7 +95,7 @@ void symbols__delete(struct rb_root *symbols);
static inline size_t symbol__size(const struct symbol *sym) static inline size_t symbol__size(const struct symbol *sym)
{ {
return sym->end - sym->start + 1; return sym->end - sym->start;
} }
struct strlist; struct strlist;
......
...@@ -214,6 +214,17 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) ...@@ -214,6 +214,17 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
goto out; 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) static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
{ {
struct thread_map *threads = NULL, *nt; struct thread_map *threads = NULL, *nt;
...@@ -224,14 +235,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) ...@@ -224,14 +235,8 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
struct strlist *slist; struct strlist *slist;
/* perf-stat expects threads to be generated even if tid not given */ /* perf-stat expects threads to be generated even if tid not given */
if (!tid_str) { if (!tid_str)
threads = malloc(sizeof(*threads) + sizeof(pid_t)); return thread_map__new_dummy();
if (threads != NULL) {
threads->map[0] = -1;
threads->nr = 1;
}
return threads;
}
slist = strlist__new(false, tid_str); slist = strlist__new(false, tid_str);
if (!slist) if (!slist)
......
...@@ -9,6 +9,7 @@ struct thread_map { ...@@ -9,6 +9,7 @@ struct thread_map {
pid_t 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_pid(pid_t pid);
struct thread_map *thread_map__new_by_tid(pid_t tid); struct thread_map *thread_map__new_by_tid(pid_t tid);
struct thread_map *thread_map__new_by_uid(uid_t uid); struct thread_map *thread_map__new_by_uid(uid_t uid);
......
...@@ -14,6 +14,14 @@ ...@@ -14,6 +14,14 @@
#include <byteswap.h> #include <byteswap.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <unistd.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... * XXX We need to find a better place for these things...
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment