Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorIngo Molnar <mingo@kernel.org>
Wed, 15 Oct 2014 09:54:14 +0000 (11:54 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 15 Oct 2014 09:54:14 +0000 (11:54 +0200)
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>
35 files changed:
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-kvm.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-top.c
tools/perf/tests/builtin-test.c
tools/perf/tests/hists_cumulate.c
tools/perf/tests/hists_filter.c
tools/perf/tests/hists_link.c
tools/perf/tests/hists_output.c
tools/perf/ui/browsers/header.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/util/annotate.c
tools/perf/util/callchain.h
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/machine.c
tools/perf/util/map.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/thread_map.c
tools/perf/util/thread_map.h
tools/perf/util/util.c

index be59394..e7417fe 100644 (file)
@@ -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);
 
index a3ce19f..8c5c11c 100644 (file)
@@ -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);
        }
 }
 
index d8bf227..460a4ce 100644 (file)
@@ -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);
index 44c6f3d..a6b2132 100644 (file)
@@ -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"
index ac145fa..2cfc4b9 100644 (file)
@@ -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);
 
index 9c9287f..891c393 100644 (file)
@@ -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);
index b9b9e58..6b4925f 100644 (file)
@@ -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;
 }
 
index fc3d55f..0aa7747 100644 (file)
@@ -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)
index ac655b0..162c978 100644 (file)
@@ -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"))
index 0ac240d..614d5c4 100644 (file)
@@ -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:
         *
index 821f581..5a31787 100644 (file)
@@ -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);
 
index d4b34b0..278ba83 100644 (file)
@@ -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;
 
index e3bbd6c..a748f2b 100644 (file)
@@ -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);
 
index 89c16b9..e8278c5 100644 (file)
@@ -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"
index 8f60a97..68eab9e 100644 (file)
@@ -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)
index f3fa425..fc654fb 100644 (file)
@@ -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;
index 3643752..7dabde1 100644 (file)
@@ -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);
index 2a1f5a4..94cfefd 100644 (file)
@@ -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;
index 7eb7107..5699e7e 100644 (file)
@@ -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;
index 3cebc9a..b4b54d8 100644 (file)
@@ -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]);
index e0868a9..d1ecde0 100644 (file)
@@ -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)
index 7bc314b..1d5c754 100644 (file)
@@ -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);
 
index 86569fa..6e88b9e 100644 (file)
@@ -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;
+}
index 8c9c70e..d0ef9a1 100644 (file)
@@ -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;
index b7d477f..34fc7c8 100644 (file)
 #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);
index b709059..2137c45 100644 (file)
@@ -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;
index 56ba07c..496f21c 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "../../perf.h"
 #include "../debug.h"
+#include "../callchain.h"
 #include "../evsel.h"
 #include "../util.h"
 #include "../event.h"
index 883406f..896bac7 100644 (file)
@@ -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;
 }
 
index ffb4404..a4be851 100644 (file)
@@ -2,7 +2,6 @@
 #define __PERF_SESSION_H
 
 #include "trace-event.h"
-#include "hist.h"
 #include "event.h"
 #include "header.h"
 #include "machine.h"
index 289df9d..4906cd8 100644 (file)
@@ -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;
 }
index be84f7a..0783311 100644 (file)
@@ -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;
index bec4b7b..eb2c19b 100644 (file)
@@ -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;
index 5d32159..f93b973 100644 (file)
@@ -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)
index 0cd8b31..95313f4 100644 (file)
@@ -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);
index 24e8d87..d5eab3f 100644 (file)
 #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...