aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-10-15 05:54:14 -0400
committerIngo Molnar <mingo@kernel.org>2014-10-15 05:54:14 -0400
commitec4212d88a77eb6caec10777ddd629b702a5ebbd (patch)
tree03b4b08df9d633e15df8c0ff27444324adf4a312 /tools
parent77654908ff1a58cee4886298968b5262884aff0b (diff)
parent2c241bd35e6f626ad6f867dcf9fefdc2315f125f (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: Infrastructure fixes and changes: * Fix off-by-one bugs in map->end handling (Stephane Eranian) * Fix off-by-one bug in maps__find(), also related to map->end handling (Namhyung Kim) * Make struct symbol->end be the first addr after the symbol range, to make it match the convention used for struct map->end. (Arnaldo Carvalho de Melo) * Fix perf_evlist__add_pollfd() error handling in 'perf kvm stat live' (Jiri Olsa) * Fix python test build by moving callchain_param to an object linked into the python binding (Jiri Olsa) * Do not include a struct hists per perf_evsel, untangling the histogram code from perf_evsel, to pave the way for exporting a minimalistic tools/lib/api/perf/ library usable by tools/perf and initially by the rasd daemon being developed by Borislav Petkov, Robert Richter and Jean Pihet. (Arnaldo Carvalho de Melo) * Make perf_evlist__open(evlist, NULL, NULL), i.e. without cpu and thread maps mean syswide monitoring, reducing the boilerplate for tools that only want system wide mode. (Arnaldo Carvalho de Melo) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-annotate.c14
-rw-r--r--tools/perf/builtin-diff.c21
-rw-r--r--tools/perf/builtin-kvm.c22
-rw-r--r--tools/perf/builtin-record.c1
-rw-r--r--tools/perf/builtin-report.c24
-rw-r--r--tools/perf/builtin-sched.c3
-rw-r--r--tools/perf/builtin-script.c1
-rw-r--r--tools/perf/builtin-top.c60
-rw-r--r--tools/perf/tests/builtin-test.c5
-rw-r--r--tools/perf/tests/hists_cumulate.c8
-rw-r--r--tools/perf/tests/hists_filter.c23
-rw-r--r--tools/perf/tests/hists_link.c23
-rw-r--r--tools/perf/tests/hists_output.c20
-rw-r--r--tools/perf/ui/browsers/header.c1
-rw-r--r--tools/perf/ui/browsers/hists.c20
-rw-r--r--tools/perf/ui/gtk/hists.c2
-rw-r--r--tools/perf/util/annotate.c8
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/event.h26
-rw-r--r--tools/perf/util/evlist.c48
-rw-r--r--tools/perf/util/evsel.c66
-rw-r--r--tools/perf/util/evsel.h14
-rw-r--r--tools/perf/util/hist.c73
-rw-r--r--tools/perf/util/hist.h49
-rw-r--r--tools/perf/util/machine.c10
-rw-r--r--tools/perf/util/map.c8
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c1
-rw-r--r--tools/perf/util/session.c23
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/sort.c4
-rw-r--r--tools/perf/util/symbol.c8
-rw-r--r--tools/perf/util/symbol.h2
-rw-r--r--tools/perf/util/thread_map.c21
-rw-r--r--tools/perf/util/thread_map.h1
-rw-r--r--tools/perf/util/util.c8
35 files changed, 392 insertions, 229 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index be5939418425..e7417fe97a97 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -51,6 +51,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
51 struct addr_location *al, 51 struct addr_location *al,
52 struct perf_annotate *ann) 52 struct perf_annotate *ann)
53{ 53{
54 struct hists *hists = evsel__hists(evsel);
54 struct hist_entry *he; 55 struct hist_entry *he;
55 int ret; 56 int ret;
56 57
@@ -66,13 +67,12 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
66 return 0; 67 return 0;
67 } 68 }
68 69
69 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0, 70 he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true);
70 true);
71 if (he == NULL) 71 if (he == NULL)
72 return -ENOMEM; 72 return -ENOMEM;
73 73
74 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 74 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
75 hists__inc_nr_samples(&evsel->hists, true); 75 hists__inc_nr_samples(hists, true);
76 return ret; 76 return ret;
77} 77}
78 78
@@ -214,6 +214,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
214 214
215 if (dump_trace) { 215 if (dump_trace) {
216 perf_session__fprintf_nr_events(session, stdout); 216 perf_session__fprintf_nr_events(session, stdout);
217 perf_evlist__fprintf_nr_events(session->evlist, stdout);
217 goto out; 218 goto out;
218 } 219 }
219 220
@@ -225,7 +226,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
225 226
226 total_nr_samples = 0; 227 total_nr_samples = 0;
227 evlist__for_each(session->evlist, pos) { 228 evlist__for_each(session->evlist, pos) {
228 struct hists *hists = &pos->hists; 229 struct hists *hists = evsel__hists(pos);
229 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; 230 u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
230 231
231 if (nr_samples > 0) { 232 if (nr_samples > 0) {
@@ -325,7 +326,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
325 "Show event group information together"), 326 "Show event group information together"),
326 OPT_END() 327 OPT_END()
327 }; 328 };
328 int ret; 329 int ret = hists__init();
330
331 if (ret < 0)
332 return ret;
329 333
330 argc = parse_options(argc, argv, options, annotate_usage, 0); 334 argc = parse_options(argc, argv, options, annotate_usage, 0);
331 335
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index a3ce19f7aebd..8c5c11ca8c53 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -327,6 +327,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
327 struct machine *machine) 327 struct machine *machine)
328{ 328{
329 struct addr_location al; 329 struct addr_location al;
330 struct hists *hists = evsel__hists(evsel);
330 331
331 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 332 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
332 pr_warning("problem processing %d event, skipping it.\n", 333 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 return -1; 335 return -1;
335 } 336 }
336 337
337 if (hists__add_entry(&evsel->hists, &al, sample->period, 338 if (hists__add_entry(hists, &al, sample->period,
338 sample->weight, sample->transaction)) { 339 sample->weight, sample->transaction)) {
339 pr_warning("problem incrementing symbol period, skipping event\n"); 340 pr_warning("problem incrementing symbol period, skipping event\n");
340 return -1; 341 return -1;
@@ -346,9 +347,9 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
346 * hists__output_resort() and precompute needs the total 347 * hists__output_resort() and precompute needs the total
347 * period in order to sort entries by percentage delta. 348 * period in order to sort entries by percentage delta.
348 */ 349 */
349 evsel->hists.stats.total_period += sample->period; 350 hists->stats.total_period += sample->period;
350 if (!al.filtered) 351 if (!al.filtered)
351 evsel->hists.stats.total_non_filtered_period += sample->period; 352 hists->stats.total_non_filtered_period += sample->period;
352 353
353 return 0; 354 return 0;
354} 355}
@@ -382,7 +383,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
382 struct perf_evsel *evsel; 383 struct perf_evsel *evsel;
383 384
384 evlist__for_each(evlist, evsel) { 385 evlist__for_each(evlist, evsel) {
385 struct hists *hists = &evsel->hists; 386 struct hists *hists = evsel__hists(evsel);
386 387
387 hists__collapse_resort(hists, NULL); 388 hists__collapse_resort(hists, NULL);
388 } 389 }
@@ -631,24 +632,26 @@ static void data_process(void)
631 bool first = true; 632 bool first = true;
632 633
633 evlist__for_each(evlist_base, evsel_base) { 634 evlist__for_each(evlist_base, evsel_base) {
635 struct hists *hists_base = evsel__hists(evsel_base);
634 struct data__file *d; 636 struct data__file *d;
635 int i; 637 int i;
636 638
637 data__for_each_file_new(i, d) { 639 data__for_each_file_new(i, d) {
638 struct perf_evlist *evlist = d->session->evlist; 640 struct perf_evlist *evlist = d->session->evlist;
639 struct perf_evsel *evsel; 641 struct perf_evsel *evsel;
642 struct hists *hists;
640 643
641 evsel = evsel_match(evsel_base, evlist); 644 evsel = evsel_match(evsel_base, evlist);
642 if (!evsel) 645 if (!evsel)
643 continue; 646 continue;
644 647
645 d->hists = &evsel->hists; 648 hists = evsel__hists(evsel);
649 d->hists = hists;
646 650
647 hists__match(&evsel_base->hists, &evsel->hists); 651 hists__match(hists_base, hists);
648 652
649 if (!show_baseline_only) 653 if (!show_baseline_only)
650 hists__link(&evsel_base->hists, 654 hists__link(hists_base, hists);
651 &evsel->hists);
652 } 655 }
653 656
654 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", 657 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
@@ -659,7 +662,7 @@ static void data_process(void)
659 if (verbose || data__files_cnt > 2) 662 if (verbose || data__files_cnt > 2)
660 data__fprintf(); 663 data__fprintf();
661 664
662 hists__process(&evsel_base->hists); 665 hists__process(hists_base);
663 } 666 }
664} 667}
665 668
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index d8bf2271f4ea..460a4ce9c044 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -896,8 +896,7 @@ static int perf_kvm__handle_stdin(void)
896 896
897static int kvm_events_live_report(struct perf_kvm_stat *kvm) 897static int kvm_events_live_report(struct perf_kvm_stat *kvm)
898{ 898{
899 struct pollfd *pollfds = NULL; 899 int nr_stdin, ret, err = -EINVAL;
900 int nr_fds, nr_stdin, ret, err = -EINVAL;
901 struct termios save; 900 struct termios save;
902 901
903 /* live flag must be set first */ 902 /* live flag must be set first */
@@ -919,34 +918,27 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
919 signal(SIGINT, sig_handler); 918 signal(SIGINT, sig_handler);
920 signal(SIGTERM, sig_handler); 919 signal(SIGTERM, sig_handler);
921 920
922 /* use pollfds -- need to add timerfd and stdin */
923 nr_fds = kvm->evlist->pollfd.nr;
924
925 /* add timer fd */ 921 /* add timer fd */
926 if (perf_kvm__timerfd_create(kvm) < 0) { 922 if (perf_kvm__timerfd_create(kvm) < 0) {
927 err = -1; 923 err = -1;
928 goto out; 924 goto out;
929 } 925 }
930 926
931 if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd)) 927 if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0)
932 goto out; 928 goto out;
933 929
934 nr_fds++; 930 nr_stdin = perf_evlist__add_pollfd(kvm->evlist, fileno(stdin));
935 931 if (nr_stdin < 0)
936 if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin)))
937 goto out; 932 goto out;
938 933
939 nr_stdin = nr_fds;
940 nr_fds++;
941 if (fd_set_nonblock(fileno(stdin)) != 0) 934 if (fd_set_nonblock(fileno(stdin)) != 0)
942 goto out; 935 goto out;
943 936
944 pollfds = kvm->evlist->pollfd.entries;
945
946 /* everything is good - enable the events and process */ 937 /* everything is good - enable the events and process */
947 perf_evlist__enable(kvm->evlist); 938 perf_evlist__enable(kvm->evlist);
948 939
949 while (!done) { 940 while (!done) {
941 struct fdarray *fda = &kvm->evlist->pollfd;
950 int rc; 942 int rc;
951 943
952 rc = perf_kvm__mmap_read(kvm); 944 rc = perf_kvm__mmap_read(kvm);
@@ -957,11 +949,11 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm)
957 if (err) 949 if (err)
958 goto out; 950 goto out;
959 951
960 if (pollfds[nr_stdin].revents & POLLIN) 952 if (fda->entries[nr_stdin].revents & POLLIN)
961 done = perf_kvm__handle_stdin(); 953 done = perf_kvm__handle_stdin();
962 954
963 if (!rc && !done) 955 if (!rc && !done)
964 err = poll(pollfds, nr_fds, 100); 956 err = fdarray__poll(fda, 100);
965 } 957 }
966 958
967 perf_evlist__disable(kvm->evlist); 959 perf_evlist__disable(kvm->evlist);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 44c6f3d55ce7..a6b2132c666f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -14,6 +14,7 @@
14#include "util/parse-options.h" 14#include "util/parse-options.h"
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16 16
17#include "util/callchain.h"
17#include "util/header.h" 18#include "util/header.h"
18#include "util/event.h" 19#include "util/event.h"
19#include "util/evlist.h" 20#include "util/evlist.h"
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index ac145fae0521..2cfc4b93991f 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -288,12 +288,14 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
288 evname = buf; 288 evname = buf;
289 289
290 for_each_group_member(pos, evsel) { 290 for_each_group_member(pos, evsel) {
291 const struct hists *pos_hists = evsel__hists(pos);
292
291 if (symbol_conf.filter_relative) { 293 if (symbol_conf.filter_relative) {
292 nr_samples += pos->hists.stats.nr_non_filtered_samples; 294 nr_samples += pos_hists->stats.nr_non_filtered_samples;
293 nr_events += pos->hists.stats.total_non_filtered_period; 295 nr_events += pos_hists->stats.total_non_filtered_period;
294 } else { 296 } else {
295 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 297 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
296 nr_events += pos->hists.stats.total_period; 298 nr_events += pos_hists->stats.total_period;
297 } 299 }
298 } 300 }
299 } 301 }
@@ -318,7 +320,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
318 struct perf_evsel *pos; 320 struct perf_evsel *pos;
319 321
320 evlist__for_each(evlist, pos) { 322 evlist__for_each(evlist, pos) {
321 struct hists *hists = &pos->hists; 323 struct hists *hists = evsel__hists(pos);
322 const char *evname = perf_evsel__name(pos); 324 const char *evname = perf_evsel__name(pos);
323 325
324 if (symbol_conf.event_group && 326 if (symbol_conf.event_group &&
@@ -427,7 +429,7 @@ static void report__collapse_hists(struct report *rep)
427 ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); 429 ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
428 430
429 evlist__for_each(rep->session->evlist, pos) { 431 evlist__for_each(rep->session->evlist, pos) {
430 struct hists *hists = &pos->hists; 432 struct hists *hists = evsel__hists(pos);
431 433
432 if (pos->idx == 0) 434 if (pos->idx == 0)
433 hists->symbol_filter_str = rep->symbol_filter_str; 435 hists->symbol_filter_str = rep->symbol_filter_str;
@@ -437,7 +439,7 @@ static void report__collapse_hists(struct report *rep)
437 /* Non-group events are considered as leader */ 439 /* Non-group events are considered as leader */
438 if (symbol_conf.event_group && 440 if (symbol_conf.event_group &&
439 !perf_evsel__is_group_leader(pos)) { 441 !perf_evsel__is_group_leader(pos)) {
440 struct hists *leader_hists = &pos->leader->hists; 442 struct hists *leader_hists = evsel__hists(pos->leader);
441 443
442 hists__match(leader_hists, hists); 444 hists__match(leader_hists, hists);
443 hists__link(leader_hists, hists); 445 hists__link(leader_hists, hists);
@@ -485,6 +487,7 @@ static int __cmd_report(struct report *rep)
485 487
486 if (dump_trace) { 488 if (dump_trace) {
487 perf_session__fprintf_nr_events(session, stdout); 489 perf_session__fprintf_nr_events(session, stdout);
490 perf_evlist__fprintf_nr_events(session->evlist, stdout);
488 return 0; 491 return 0;
489 } 492 }
490 } 493 }
@@ -500,7 +503,7 @@ static int __cmd_report(struct report *rep)
500 } 503 }
501 504
502 evlist__for_each(session->evlist, pos) 505 evlist__for_each(session->evlist, pos)
503 hists__output_resort(&pos->hists); 506 hists__output_resort(evsel__hists(pos));
504 507
505 return report__browse_hists(rep); 508 return report__browse_hists(rep);
506} 509}
@@ -565,7 +568,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
565 struct stat st; 568 struct stat st;
566 bool has_br_stack = false; 569 bool has_br_stack = false;
567 int branch_mode = -1; 570 int branch_mode = -1;
568 int ret = -1;
569 char callchain_default_opt[] = "fractal,0.5,callee"; 571 char callchain_default_opt[] = "fractal,0.5,callee";
570 const char * const report_usage[] = { 572 const char * const report_usage[] = {
571 "perf report [<options>]", 573 "perf report [<options>]",
@@ -692,6 +694,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
692 struct perf_data_file file = { 694 struct perf_data_file file = {
693 .mode = PERF_DATA_MODE_READ, 695 .mode = PERF_DATA_MODE_READ,
694 }; 696 };
697 int ret = hists__init();
698
699 if (ret < 0)
700 return ret;
695 701
696 perf_config(report__config, &report); 702 perf_config(report__config, &report);
697 703
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 9c9287fbf8e9..891c3930080e 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1431,9 +1431,6 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1431{ 1431{
1432 int err = 0; 1432 int err = 0;
1433 1433
1434 evsel->hists.stats.total_period += sample->period;
1435 hists__inc_nr_samples(&evsel->hists, true);
1436
1437 if (evsel->handler != NULL) { 1434 if (evsel->handler != NULL) {
1438 tracepoint_handler f = evsel->handler; 1435 tracepoint_handler f = evsel->handler;
1439 err = f(tool, evsel, sample, machine); 1436 err = f(tool, evsel, sample, machine);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index b9b9e58a6c39..6b4925f65bf0 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -572,7 +572,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
572 572
573 scripting_ops->process_event(event, sample, evsel, thread, &al); 573 scripting_ops->process_event(event, sample, evsel, thread, &al);
574 574
575 evsel->hists.stats.total_period += sample->period;
576 return 0; 575 return 0;
577} 576}
578 577
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index fc3d55f832ac..0aa7747ff139 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -251,6 +251,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
251 char bf[160]; 251 char bf[160];
252 int printed = 0; 252 int printed = 0;
253 const int win_width = top->winsize.ws_col - 1; 253 const int win_width = top->winsize.ws_col - 1;
254 struct hists *hists = evsel__hists(top->sym_evsel);
254 255
255 puts(CONSOLE_CLEAR); 256 puts(CONSOLE_CLEAR);
256 257
@@ -261,13 +262,13 @@ static void perf_top__print_sym_table(struct perf_top *top)
261 262
262 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 263 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
263 264
264 if (top->sym_evsel->hists.stats.nr_lost_warned != 265 if (hists->stats.nr_lost_warned !=
265 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { 266 hists->stats.nr_events[PERF_RECORD_LOST]) {
266 top->sym_evsel->hists.stats.nr_lost_warned = 267 hists->stats.nr_lost_warned =
267 top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 268 hists->stats.nr_events[PERF_RECORD_LOST];
268 color_fprintf(stdout, PERF_COLOR_RED, 269 color_fprintf(stdout, PERF_COLOR_RED,
269 "WARNING: LOST %d chunks, Check IO/CPU overload", 270 "WARNING: LOST %d chunks, Check IO/CPU overload",
270 top->sym_evsel->hists.stats.nr_lost_warned); 271 hists->stats.nr_lost_warned);
271 ++printed; 272 ++printed;
272 } 273 }
273 274
@@ -277,21 +278,18 @@ static void perf_top__print_sym_table(struct perf_top *top)
277 } 278 }
278 279
279 if (top->zero) { 280 if (top->zero) {
280 hists__delete_entries(&top->sym_evsel->hists); 281 hists__delete_entries(hists);
281 } else { 282 } else {
282 hists__decay_entries(&top->sym_evsel->hists, 283 hists__decay_entries(hists, top->hide_user_symbols,
283 top->hide_user_symbols,
284 top->hide_kernel_symbols); 284 top->hide_kernel_symbols);
285 } 285 }
286 286
287 hists__collapse_resort(&top->sym_evsel->hists, NULL); 287 hists__collapse_resort(hists, NULL);
288 hists__output_resort(&top->sym_evsel->hists); 288 hists__output_resort(hists);
289 289
290 hists__output_recalc_col_len(&top->sym_evsel->hists, 290 hists__output_recalc_col_len(hists, top->print_entries - printed);
291 top->print_entries - printed);
292 putchar('\n'); 291 putchar('\n');
293 hists__fprintf(&top->sym_evsel->hists, false, 292 hists__fprintf(hists, false, top->print_entries - printed, win_width,
294 top->print_entries - printed, win_width,
295 top->min_percent, stdout); 293 top->min_percent, stdout);
296} 294}
297 295
@@ -334,6 +332,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
334{ 332{
335 char *buf = malloc(0), *p; 333 char *buf = malloc(0), *p;
336 struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; 334 struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
335 struct hists *hists = evsel__hists(top->sym_evsel);
337 struct rb_node *next; 336 struct rb_node *next;
338 size_t dummy = 0; 337 size_t dummy = 0;
339 338
@@ -351,7 +350,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
351 if (p) 350 if (p)
352 *p = 0; 351 *p = 0;
353 352
354 next = rb_first(&top->sym_evsel->hists.entries); 353 next = rb_first(&hists->entries);
355 while (next) { 354 while (next) {
356 n = rb_entry(next, struct hist_entry, rb_node); 355 n = rb_entry(next, struct hist_entry, rb_node);
357 if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { 356 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)
538static void perf_top__sort_new_samples(void *arg) 537static void perf_top__sort_new_samples(void *arg)
539{ 538{
540 struct perf_top *t = arg; 539 struct perf_top *t = arg;
540 struct hists *hists;
541
541 perf_top__reset_sample_counters(t); 542 perf_top__reset_sample_counters(t);
542 543
543 if (t->evlist->selected != NULL) 544 if (t->evlist->selected != NULL)
544 t->sym_evsel = t->evlist->selected; 545 t->sym_evsel = t->evlist->selected;
545 546
547 hists = evsel__hists(t->sym_evsel);
548
546 if (t->zero) { 549 if (t->zero) {
547 hists__delete_entries(&t->sym_evsel->hists); 550 hists__delete_entries(hists);
548 } else { 551 } else {
549 hists__decay_entries(&t->sym_evsel->hists, 552 hists__decay_entries(hists, t->hide_user_symbols,
550 t->hide_user_symbols,
551 t->hide_kernel_symbols); 553 t->hide_kernel_symbols);
552 } 554 }
553 555
554 hists__collapse_resort(&t->sym_evsel->hists, NULL); 556 hists__collapse_resort(hists, NULL);
555 hists__output_resort(&t->sym_evsel->hists); 557 hists__output_resort(hists);
556} 558}
557 559
558static void *display_thread_tui(void *arg) 560static void *display_thread_tui(void *arg)
@@ -573,8 +575,10 @@ static void *display_thread_tui(void *arg)
573 * Zooming in/out UIDs. For now juse use whatever the user passed 575 * Zooming in/out UIDs. For now juse use whatever the user passed
574 * via --uid. 576 * via --uid.
575 */ 577 */
576 evlist__for_each(top->evlist, pos) 578 evlist__for_each(top->evlist, pos) {
577 pos->hists.uid_filter_str = top->record_opts.target.uid_str; 579 struct hists *hists = evsel__hists(pos);
580 hists->uid_filter_str = top->record_opts.target.uid_str;
581 }
578 582
579 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, 583 perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
580 &top->session->header.env); 584 &top->session->header.env);
@@ -768,6 +772,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
768 } 772 }
769 773
770 if (al.sym == NULL || !al.sym->ignore) { 774 if (al.sym == NULL || !al.sym->ignore) {
775 struct hists *hists = evsel__hists(evsel);
771 struct hist_entry_iter iter = { 776 struct hist_entry_iter iter = {
772 .add_entry_cb = hist_iter__top_callback, 777 .add_entry_cb = hist_iter__top_callback,
773 }; 778 };
@@ -777,14 +782,14 @@ static void perf_event__process_sample(struct perf_tool *tool,
777 else 782 else
778 iter.ops = &hist_iter_normal; 783 iter.ops = &hist_iter_normal;
779 784
780 pthread_mutex_lock(&evsel->hists.lock); 785 pthread_mutex_lock(&hists->lock);
781 786
782 err = hist_entry_iter__add(&iter, &al, evsel, sample, 787 err = hist_entry_iter__add(&iter, &al, evsel, sample,
783 top->max_stack, top); 788 top->max_stack, top);
784 if (err < 0) 789 if (err < 0)
785 pr_err("Problem incrementing symbol period, skipping event\n"); 790 pr_err("Problem incrementing symbol period, skipping event\n");
786 791
787 pthread_mutex_unlock(&evsel->hists.lock); 792 pthread_mutex_unlock(&hists->lock);
788 } 793 }
789 794
790 return; 795 return;
@@ -849,7 +854,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
849 perf_event__process_sample(&top->tool, event, evsel, 854 perf_event__process_sample(&top->tool, event, evsel,
850 &sample, machine); 855 &sample, machine);
851 } else if (event->header.type < PERF_RECORD_MAX) { 856 } else if (event->header.type < PERF_RECORD_MAX) {
852 hists__inc_nr_events(&evsel->hists, event->header.type); 857 hists__inc_nr_events(evsel__hists(evsel), event->header.type);
853 machine__process_event(machine, event, &sample); 858 machine__process_event(machine, event, &sample);
854 } else 859 } else
855 ++session->stats.nr_unknown_events; 860 ++session->stats.nr_unknown_events;
@@ -1042,7 +1047,6 @@ parse_percent_limit(const struct option *opt, const char *arg,
1042 1047
1043int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) 1048int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1044{ 1049{
1045 int status = -1;
1046 char errbuf[BUFSIZ]; 1050 char errbuf[BUFSIZ];
1047 struct perf_top top = { 1051 struct perf_top top = {
1048 .count_filter = 5, 1052 .count_filter = 5,
@@ -1160,6 +1164,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1160 "perf top [<options>]", 1164 "perf top [<options>]",
1161 NULL 1165 NULL
1162 }; 1166 };
1167 int status = hists__init();
1168
1169 if (status < 0)
1170 return status;
1163 1171
1164 top.evlist = perf_evlist__new(); 1172 top.evlist = perf_evlist__new();
1165 if (top.evlist == NULL) 1173 if (top.evlist == NULL)
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index ac655b0700e7..162c978f1491 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -6,6 +6,7 @@
6#include <unistd.h> 6#include <unistd.h>
7#include <string.h> 7#include <string.h>
8#include "builtin.h" 8#include "builtin.h"
9#include "hist.h"
9#include "intlist.h" 10#include "intlist.h"
10#include "tests.h" 11#include "tests.h"
11#include "debug.h" 12#include "debug.h"
@@ -302,6 +303,10 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
302 OPT_END() 303 OPT_END()
303 }; 304 };
304 struct intlist *skiplist = NULL; 305 struct intlist *skiplist = NULL;
306 int ret = hists__init();
307
308 if (ret < 0)
309 return ret;
305 310
306 argc = parse_options(argc, argv, test_options, test_usage, 0); 311 argc = parse_options(argc, argv, test_options, test_usage, 0);
307 if (argc >= 1 && !strcmp(argv[0], "list")) 312 if (argc >= 1 && !strcmp(argv[0], "list"))
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 0ac240db2e24..614d5c4978ab 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -245,7 +245,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec
245static int test1(struct perf_evsel *evsel, struct machine *machine) 245static int test1(struct perf_evsel *evsel, struct machine *machine)
246{ 246{
247 int err; 247 int err;
248 struct hists *hists = &evsel->hists; 248 struct hists *hists = evsel__hists(evsel);
249 /* 249 /*
250 * expected output: 250 * expected output:
251 * 251 *
@@ -295,7 +295,7 @@ out:
295static int test2(struct perf_evsel *evsel, struct machine *machine) 295static int test2(struct perf_evsel *evsel, struct machine *machine)
296{ 296{
297 int err; 297 int err;
298 struct hists *hists = &evsel->hists; 298 struct hists *hists = evsel__hists(evsel);
299 /* 299 /*
300 * expected output: 300 * expected output:
301 * 301 *
@@ -442,7 +442,7 @@ out:
442static int test3(struct perf_evsel *evsel, struct machine *machine) 442static int test3(struct perf_evsel *evsel, struct machine *machine)
443{ 443{
444 int err; 444 int err;
445 struct hists *hists = &evsel->hists; 445 struct hists *hists = evsel__hists(evsel);
446 /* 446 /*
447 * expected output: 447 * expected output:
448 * 448 *
@@ -498,7 +498,7 @@ out:
498static int test4(struct perf_evsel *evsel, struct machine *machine) 498static int test4(struct perf_evsel *evsel, struct machine *machine)
499{ 499{
500 int err; 500 int err;
501 struct hists *hists = &evsel->hists; 501 struct hists *hists = evsel__hists(evsel);
502 /* 502 /*
503 * expected output: 503 * expected output:
504 * 504 *
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 821f581fd930..5a31787cc6b9 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -66,11 +66,12 @@ static int add_hist_entries(struct perf_evlist *evlist,
66 .ops = &hist_iter_normal, 66 .ops = &hist_iter_normal,
67 .hide_unresolved = false, 67 .hide_unresolved = false,
68 }; 68 };
69 struct hists *hists = evsel__hists(evsel);
69 70
70 /* make sure it has no filter at first */ 71 /* make sure it has no filter at first */
71 evsel->hists.thread_filter = NULL; 72 hists->thread_filter = NULL;
72 evsel->hists.dso_filter = NULL; 73 hists->dso_filter = NULL;
73 evsel->hists.symbol_filter_str = NULL; 74 hists->symbol_filter_str = NULL;
74 75
75 sample.pid = fake_samples[i].pid; 76 sample.pid = fake_samples[i].pid;
76 sample.tid = fake_samples[i].pid; 77 sample.tid = fake_samples[i].pid;
@@ -134,7 +135,7 @@ int test__hists_filter(void)
134 goto out; 135 goto out;
135 136
136 evlist__for_each(evlist, evsel) { 137 evlist__for_each(evlist, evsel) {
137 struct hists *hists = &evsel->hists; 138 struct hists *hists = evsel__hists(evsel);
138 139
139 hists__collapse_resort(hists, NULL); 140 hists__collapse_resort(hists, NULL);
140 hists__output_resort(hists); 141 hists__output_resort(hists);
@@ -160,7 +161,7 @@ int test__hists_filter(void)
160 hists->stats.total_non_filtered_period); 161 hists->stats.total_non_filtered_period);
161 162
162 /* now applying thread filter for 'bash' */ 163 /* now applying thread filter for 'bash' */
163 evsel->hists.thread_filter = fake_samples[9].thread; 164 hists->thread_filter = fake_samples[9].thread;
164 hists__filter_by_thread(hists); 165 hists__filter_by_thread(hists);
165 166
166 if (verbose > 2) { 167 if (verbose > 2) {
@@ -185,11 +186,11 @@ int test__hists_filter(void)
185 hists->stats.total_non_filtered_period == 400); 186 hists->stats.total_non_filtered_period == 400);
186 187
187 /* remove thread filter first */ 188 /* remove thread filter first */
188 evsel->hists.thread_filter = NULL; 189 hists->thread_filter = NULL;
189 hists__filter_by_thread(hists); 190 hists__filter_by_thread(hists);
190 191
191 /* now applying dso filter for 'kernel' */ 192 /* now applying dso filter for 'kernel' */
192 evsel->hists.dso_filter = fake_samples[0].map->dso; 193 hists->dso_filter = fake_samples[0].map->dso;
193 hists__filter_by_dso(hists); 194 hists__filter_by_dso(hists);
194 195
195 if (verbose > 2) { 196 if (verbose > 2) {
@@ -214,7 +215,7 @@ int test__hists_filter(void)
214 hists->stats.total_non_filtered_period == 300); 215 hists->stats.total_non_filtered_period == 300);
215 216
216 /* remove dso filter first */ 217 /* remove dso filter first */
217 evsel->hists.dso_filter = NULL; 218 hists->dso_filter = NULL;
218 hists__filter_by_dso(hists); 219 hists__filter_by_dso(hists);
219 220
220 /* 221 /*
@@ -224,7 +225,7 @@ int test__hists_filter(void)
224 * be counted as a separate entry but the sample count and 225 * be counted as a separate entry but the sample count and
225 * total period will be remained. 226 * total period will be remained.
226 */ 227 */
227 evsel->hists.symbol_filter_str = "main"; 228 hists->symbol_filter_str = "main";
228 hists__filter_by_symbol(hists); 229 hists__filter_by_symbol(hists);
229 230
230 if (verbose > 2) { 231 if (verbose > 2) {
@@ -249,8 +250,8 @@ int test__hists_filter(void)
249 hists->stats.total_non_filtered_period == 300); 250 hists->stats.total_non_filtered_period == 300);
250 251
251 /* now applying all filters at once. */ 252 /* now applying all filters at once. */
252 evsel->hists.thread_filter = fake_samples[1].thread; 253 hists->thread_filter = fake_samples[1].thread;
253 evsel->hists.dso_filter = fake_samples[1].map->dso; 254 hists->dso_filter = fake_samples[1].map->dso;
254 hists__filter_by_thread(hists); 255 hists__filter_by_thread(hists);
255 hists__filter_by_dso(hists); 256 hists__filter_by_dso(hists);
256 257
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index d4b34b0f50a2..278ba8344c23 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -73,6 +73,8 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
73 * "bash [libc] malloc" so total 9 entries will be in the tree. 73 * "bash [libc] malloc" so total 9 entries will be in the tree.
74 */ 74 */
75 evlist__for_each(evlist, evsel) { 75 evlist__for_each(evlist, evsel) {
76 struct hists *hists = evsel__hists(evsel);
77
76 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 78 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
77 const union perf_event event = { 79 const union perf_event event = {
78 .header = { 80 .header = {
@@ -87,7 +89,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
87 &sample) < 0) 89 &sample) < 0)
88 goto out; 90 goto out;
89 91
90 he = __hists__add_entry(&evsel->hists, &al, NULL, 92 he = __hists__add_entry(hists, &al, NULL,
91 NULL, NULL, 1, 1, 0, true); 93 NULL, NULL, 1, 1, 0, true);
92 if (he == NULL) 94 if (he == NULL)
93 goto out; 95 goto out;
@@ -111,7 +113,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
111 &sample) < 0) 113 &sample) < 0)
112 goto out; 114 goto out;
113 115
114 he = __hists__add_entry(&evsel->hists, &al, NULL, 116 he = __hists__add_entry(hists, &al, NULL,
115 NULL, NULL, 1, 1, 0, true); 117 NULL, NULL, 1, 1, 0, true);
116 if (he == NULL) 118 if (he == NULL)
117 goto out; 119 goto out;
@@ -271,6 +273,7 @@ static int validate_link(struct hists *leader, struct hists *other)
271int test__hists_link(void) 273int test__hists_link(void)
272{ 274{
273 int err = -1; 275 int err = -1;
276 struct hists *hists, *first_hists;
274 struct machines machines; 277 struct machines machines;
275 struct machine *machine = NULL; 278 struct machine *machine = NULL;
276 struct perf_evsel *evsel, *first; 279 struct perf_evsel *evsel, *first;
@@ -306,24 +309,28 @@ int test__hists_link(void)
306 goto out; 309 goto out;
307 310
308 evlist__for_each(evlist, evsel) { 311 evlist__for_each(evlist, evsel) {
309 hists__collapse_resort(&evsel->hists, NULL); 312 hists = evsel__hists(evsel);
313 hists__collapse_resort(hists, NULL);
310 314
311 if (verbose > 2) 315 if (verbose > 2)
312 print_hists_in(&evsel->hists); 316 print_hists_in(hists);
313 } 317 }
314 318
315 first = perf_evlist__first(evlist); 319 first = perf_evlist__first(evlist);
316 evsel = perf_evlist__last(evlist); 320 evsel = perf_evlist__last(evlist);
317 321
322 first_hists = evsel__hists(first);
323 hists = evsel__hists(evsel);
324
318 /* match common entries */ 325 /* match common entries */
319 hists__match(&first->hists, &evsel->hists); 326 hists__match(first_hists, hists);
320 err = validate_match(&first->hists, &evsel->hists); 327 err = validate_match(first_hists, hists);
321 if (err) 328 if (err)
322 goto out; 329 goto out;
323 330
324 /* link common and/or dummy entries */ 331 /* link common and/or dummy entries */
325 hists__link(&first->hists, &evsel->hists); 332 hists__link(first_hists, hists);
326 err = validate_link(&first->hists, &evsel->hists); 333 err = validate_link(first_hists, hists);
327 if (err) 334 if (err)
328 goto out; 335 goto out;
329 336
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index e3bbd6c54c1b..a748f2be1222 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -122,7 +122,7 @@ typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
122static int test1(struct perf_evsel *evsel, struct machine *machine) 122static int test1(struct perf_evsel *evsel, struct machine *machine)
123{ 123{
124 int err; 124 int err;
125 struct hists *hists = &evsel->hists; 125 struct hists *hists = evsel__hists(evsel);
126 struct hist_entry *he; 126 struct hist_entry *he;
127 struct rb_root *root; 127 struct rb_root *root;
128 struct rb_node *node; 128 struct rb_node *node;
@@ -159,7 +159,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
159 print_hists_out(hists); 159 print_hists_out(hists);
160 } 160 }
161 161
162 root = &evsel->hists.entries; 162 root = &hists->entries;
163 node = rb_first(root); 163 node = rb_first(root);
164 he = rb_entry(node, struct hist_entry, rb_node); 164 he = rb_entry(node, struct hist_entry, rb_node);
165 TEST_ASSERT_VAL("Invalid hist entry", 165 TEST_ASSERT_VAL("Invalid hist entry",
@@ -224,7 +224,7 @@ out:
224static int test2(struct perf_evsel *evsel, struct machine *machine) 224static int test2(struct perf_evsel *evsel, struct machine *machine)
225{ 225{
226 int err; 226 int err;
227 struct hists *hists = &evsel->hists; 227 struct hists *hists = evsel__hists(evsel);
228 struct hist_entry *he; 228 struct hist_entry *he;
229 struct rb_root *root; 229 struct rb_root *root;
230 struct rb_node *node; 230 struct rb_node *node;
@@ -259,7 +259,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
259 print_hists_out(hists); 259 print_hists_out(hists);
260 } 260 }
261 261
262 root = &evsel->hists.entries; 262 root = &hists->entries;
263 node = rb_first(root); 263 node = rb_first(root);
264 he = rb_entry(node, struct hist_entry, rb_node); 264 he = rb_entry(node, struct hist_entry, rb_node);
265 TEST_ASSERT_VAL("Invalid hist entry", 265 TEST_ASSERT_VAL("Invalid hist entry",
@@ -280,7 +280,7 @@ out:
280static int test3(struct perf_evsel *evsel, struct machine *machine) 280static int test3(struct perf_evsel *evsel, struct machine *machine)
281{ 281{
282 int err; 282 int err;
283 struct hists *hists = &evsel->hists; 283 struct hists *hists = evsel__hists(evsel);
284 struct hist_entry *he; 284 struct hist_entry *he;
285 struct rb_root *root; 285 struct rb_root *root;
286 struct rb_node *node; 286 struct rb_node *node;
@@ -313,7 +313,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
313 print_hists_out(hists); 313 print_hists_out(hists);
314 } 314 }
315 315
316 root = &evsel->hists.entries; 316 root = &hists->entries;
317 node = rb_first(root); 317 node = rb_first(root);
318 he = rb_entry(node, struct hist_entry, rb_node); 318 he = rb_entry(node, struct hist_entry, rb_node);
319 TEST_ASSERT_VAL("Invalid hist entry", 319 TEST_ASSERT_VAL("Invalid hist entry",
@@ -354,7 +354,7 @@ out:
354static int test4(struct perf_evsel *evsel, struct machine *machine) 354static int test4(struct perf_evsel *evsel, struct machine *machine)
355{ 355{
356 int err; 356 int err;
357 struct hists *hists = &evsel->hists; 357 struct hists *hists = evsel__hists(evsel);
358 struct hist_entry *he; 358 struct hist_entry *he;
359 struct rb_root *root; 359 struct rb_root *root;
360 struct rb_node *node; 360 struct rb_node *node;
@@ -391,7 +391,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
391 print_hists_out(hists); 391 print_hists_out(hists);
392 } 392 }
393 393
394 root = &evsel->hists.entries; 394 root = &hists->entries;
395 node = rb_first(root); 395 node = rb_first(root);
396 he = rb_entry(node, struct hist_entry, rb_node); 396 he = rb_entry(node, struct hist_entry, rb_node);
397 TEST_ASSERT_VAL("Invalid hist entry", 397 TEST_ASSERT_VAL("Invalid hist entry",
@@ -456,7 +456,7 @@ out:
456static int test5(struct perf_evsel *evsel, struct machine *machine) 456static int test5(struct perf_evsel *evsel, struct machine *machine)
457{ 457{
458 int err; 458 int err;
459 struct hists *hists = &evsel->hists; 459 struct hists *hists = evsel__hists(evsel);
460 struct hist_entry *he; 460 struct hist_entry *he;
461 struct rb_root *root; 461 struct rb_root *root;
462 struct rb_node *node; 462 struct rb_node *node;
@@ -494,7 +494,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
494 print_hists_out(hists); 494 print_hists_out(hists);
495 } 495 }
496 496
497 root = &evsel->hists.entries; 497 root = &hists->entries;
498 node = rb_first(root); 498 node = rb_first(root);
499 he = rb_entry(node, struct hist_entry, rb_node); 499 he = rb_entry(node, struct hist_entry, rb_node);
500 500
diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c
index 89c16b988618..e8278c558d4a 100644
--- a/tools/perf/ui/browsers/header.c
+++ b/tools/perf/ui/browsers/header.c
@@ -1,6 +1,7 @@
1#include "util/cache.h" 1#include "util/cache.h"
2#include "util/debug.h" 2#include "util/debug.h"
3#include "ui/browser.h" 3#include "ui/browser.h"
4#include "ui/keysyms.h"
4#include "ui/ui.h" 5#include "ui/ui.h"
5#include "ui/util.h" 6#include "ui/util.h"
6#include "ui/libslang.h" 7#include "ui/libslang.h"
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 8f60a970404f..68eab9ea1634 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1229,12 +1229,14 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size)
1229 ev_name = buf; 1229 ev_name = buf;
1230 1230
1231 for_each_group_member(pos, evsel) { 1231 for_each_group_member(pos, evsel) {
1232 struct hists *pos_hists = evsel__hists(pos);
1233
1232 if (symbol_conf.filter_relative) { 1234 if (symbol_conf.filter_relative) {
1233 nr_samples += pos->hists.stats.nr_non_filtered_samples; 1235 nr_samples += pos_hists->stats.nr_non_filtered_samples;
1234 nr_events += pos->hists.stats.total_non_filtered_period; 1236 nr_events += pos_hists->stats.total_non_filtered_period;
1235 } else { 1237 } else {
1236 nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1238 nr_samples += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1237 nr_events += pos->hists.stats.total_period; 1239 nr_events += pos_hists->stats.total_period;
1238 } 1240 }
1239 } 1241 }
1240 } 1242 }
@@ -1387,7 +1389,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1387 float min_pcnt, 1389 float min_pcnt,
1388 struct perf_session_env *env) 1390 struct perf_session_env *env)
1389{ 1391{
1390 struct hists *hists = &evsel->hists; 1392 struct hists *hists = evsel__hists(evsel);
1391 struct hist_browser *browser = hist_browser__new(hists); 1393 struct hist_browser *browser = hist_browser__new(hists);
1392 struct branch_info *bi; 1394 struct branch_info *bi;
1393 struct pstack *fstack; 1395 struct pstack *fstack;
@@ -1802,8 +1804,9 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1802 struct perf_evsel_menu *menu = container_of(browser, 1804 struct perf_evsel_menu *menu = container_of(browser,
1803 struct perf_evsel_menu, b); 1805 struct perf_evsel_menu, b);
1804 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); 1806 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1807 struct hists *hists = evsel__hists(evsel);
1805 bool current_entry = ui_browser__is_current_entry(browser, row); 1808 bool current_entry = ui_browser__is_current_entry(browser, row);
1806 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1809 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
1807 const char *ev_name = perf_evsel__name(evsel); 1810 const char *ev_name = perf_evsel__name(evsel);
1808 char bf[256], unit; 1811 char bf[256], unit;
1809 const char *warn = " "; 1812 const char *warn = " ";
@@ -1818,7 +1821,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1818 ev_name = perf_evsel__group_name(evsel); 1821 ev_name = perf_evsel__group_name(evsel);
1819 1822
1820 for_each_group_member(pos, evsel) { 1823 for_each_group_member(pos, evsel) {
1821 nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; 1824 struct hists *pos_hists = evsel__hists(pos);
1825 nr_events += pos_hists->stats.nr_events[PERF_RECORD_SAMPLE];
1822 } 1826 }
1823 } 1827 }
1824 1828
@@ -1827,7 +1831,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
1827 unit, unit == ' ' ? "" : " ", ev_name); 1831 unit, unit == ' ' ? "" : " ", ev_name);
1828 slsmg_printf("%s", bf); 1832 slsmg_printf("%s", bf);
1829 1833
1830 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST]; 1834 nr_events = hists->stats.nr_events[PERF_RECORD_LOST];
1831 if (nr_events != 0) { 1835 if (nr_events != 0) {
1832 menu->lost_events = true; 1836 menu->lost_events = true;
1833 if (!current_entry) 1837 if (!current_entry)
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index f3fa4258b256..fc654fb77ace 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -319,7 +319,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
319 gtk_container_add(GTK_CONTAINER(window), vbox); 319 gtk_container_add(GTK_CONTAINER(window), vbox);
320 320
321 evlist__for_each(evlist, pos) { 321 evlist__for_each(evlist, pos) {
322 struct hists *hists = &pos->hists; 322 struct hists *hists = evsel__hists(pos);
323 const char *evname = perf_evsel__name(pos); 323 const char *evname = perf_evsel__name(pos);
324 GtkWidget *scrolled_window; 324 GtkWidget *scrolled_window;
325 GtkWidget *tab_label; 325 GtkWidget *tab_label;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 36437527dbb3..7dabde14ea54 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -478,7 +478,7 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
478 478
479 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); 479 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
480 480
481 if (addr < sym->start || addr > sym->end) 481 if (addr < sym->start || addr >= sym->end)
482 return -ERANGE; 482 return -ERANGE;
483 483
484 offset = addr - sym->start; 484 offset = addr - sym->start;
@@ -836,7 +836,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
836 end = map__rip_2objdump(map, sym->end); 836 end = map__rip_2objdump(map, sym->end);
837 837
838 offset = line_ip - start; 838 offset = line_ip - start;
839 if ((u64)line_ip < start || (u64)line_ip > end) 839 if ((u64)line_ip < start || (u64)line_ip >= end)
840 offset = -1; 840 offset = -1;
841 else 841 else
842 parsed_line = tmp2 + 1; 842 parsed_line = tmp2 + 1;
@@ -966,7 +966,7 @@ fallback:
966 kce.kcore_filename = symfs_filename; 966 kce.kcore_filename = symfs_filename;
967 kce.addr = map__rip_2objdump(map, sym->start); 967 kce.addr = map__rip_2objdump(map, sym->start);
968 kce.offs = sym->start; 968 kce.offs = sym->start;
969 kce.len = sym->end + 1 - sym->start; 969 kce.len = sym->end - sym->start;
970 if (!kcore_extract__create(&kce)) { 970 if (!kcore_extract__create(&kce)) {
971 delete_extract = true; 971 delete_extract = true;
972 strlcpy(symfs_filename, kce.extract_filename, 972 strlcpy(symfs_filename, kce.extract_filename,
@@ -987,7 +987,7 @@ fallback:
987 disassembler_style ? "-M " : "", 987 disassembler_style ? "-M " : "",
988 disassembler_style ? disassembler_style : "", 988 disassembler_style ? disassembler_style : "",
989 map__rip_2objdump(map, sym->start), 989 map__rip_2objdump(map, sym->start),
990 map__rip_2objdump(map, sym->end+1), 990 map__rip_2objdump(map, sym->end),
991 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", 991 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
992 symbol_conf.annotate_src ? "-S" : "", 992 symbol_conf.annotate_src ? "-S" : "",
993 symfs_filename, filename); 993 symfs_filename, filename);
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 2a1f5a46543a..94cfefddf4db 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -65,6 +65,8 @@ struct callchain_param {
65 enum chain_key key; 65 enum chain_key key;
66}; 66};
67 67
68extern struct callchain_param callchain_param;
69
68struct callchain_list { 70struct callchain_list {
69 u64 ip; 71 u64 ip;
70 struct map_symbol ms; 72 struct map_symbol ms;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 7eb7107731ec..5699e7e2a790 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -190,6 +190,32 @@ enum perf_user_event_type { /* above any possible kernel type */
190 PERF_RECORD_HEADER_MAX 190 PERF_RECORD_HEADER_MAX
191}; 191};
192 192
193/*
194 * The kernel collects the number of events it couldn't send in a stretch and
195 * when possible sends this number in a PERF_RECORD_LOST event. The number of
196 * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while
197 * total_lost tells exactly how many events the kernel in fact lost, i.e. it is
198 * the sum of all struct lost_event.lost fields reported.
199 *
200 * The total_period is needed because by default auto-freq is used, so
201 * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get
202 * the total number of low level events, it is necessary to to sum all struct
203 * sample_event.period and stash the result in total_period.
204 */
205struct events_stats {
206 u64 total_period;
207 u64 total_non_filtered_period;
208 u64 total_lost;
209 u64 total_invalid_chains;
210 u32 nr_events[PERF_RECORD_HEADER_MAX];
211 u32 nr_non_filtered_samples;
212 u32 nr_lost_warned;
213 u32 nr_unknown_events;
214 u32 nr_invalid_chains;
215 u32 nr_unknown_id;
216 u32 nr_unprocessable_samples;
217};
218
193struct attr_event { 219struct attr_event {
194 struct perf_event_header header; 220 struct perf_event_header header;
195 struct perf_event_attr attr; 221 struct perf_event_attr attr;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3cebc9a8d52e..b4b54d84e9b0 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1175,11 +1175,51 @@ void perf_evlist__close(struct perf_evlist *evlist)
1175 } 1175 }
1176} 1176}
1177 1177
1178static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist)
1179{
1180 int err = -ENOMEM;
1181
1182 /*
1183 * Try reading /sys/devices/system/cpu/online to get
1184 * an all cpus map.
1185 *
1186 * FIXME: -ENOMEM is the best we can do here, the cpu_map
1187 * code needs an overhaul to properly forward the
1188 * error, and we may not want to do that fallback to a
1189 * default cpu identity map :-\
1190 */
1191 evlist->cpus = cpu_map__new(NULL);
1192 if (evlist->cpus == NULL)
1193 goto out;
1194
1195 evlist->threads = thread_map__new_dummy();
1196 if (evlist->threads == NULL)
1197 goto out_free_cpus;
1198
1199 err = 0;
1200out:
1201 return err;
1202out_free_cpus:
1203 cpu_map__delete(evlist->cpus);
1204 evlist->cpus = NULL;
1205 goto out;
1206}
1207
1178int perf_evlist__open(struct perf_evlist *evlist) 1208int perf_evlist__open(struct perf_evlist *evlist)
1179{ 1209{
1180 struct perf_evsel *evsel; 1210 struct perf_evsel *evsel;
1181 int err; 1211 int err;
1182 1212
1213 /*
1214 * Default: one fd per CPU, all threads, aka systemwide
1215 * as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL
1216 */
1217 if (evlist->threads == NULL && evlist->cpus == NULL) {
1218 err = perf_evlist__create_syswide_maps(evlist);
1219 if (err < 0)
1220 goto out_err;
1221 }
1222
1183 perf_evlist__update_id_pos(evlist); 1223 perf_evlist__update_id_pos(evlist);
1184 1224
1185 evlist__for_each(evlist, evsel) { 1225 evlist__for_each(evlist, evsel) {
@@ -1276,8 +1316,14 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
1276 sigaction(SIGUSR1, &act, NULL); 1316 sigaction(SIGUSR1, &act, NULL);
1277 } 1317 }
1278 1318
1279 if (target__none(target)) 1319 if (target__none(target)) {
1320 if (evlist->threads == NULL) {
1321 fprintf(stderr, "FATAL: evlist->threads need to be set at this point (%s:%d).\n",
1322 __func__, __LINE__);
1323 goto out_close_pipes;
1324 }
1280 evlist->threads->map[0] = evlist->workload.pid; 1325 evlist->threads->map[0] = evlist->workload.pid;
1326 }
1281 1327
1282 close(child_ready_pipe[1]); 1328 close(child_ready_pipe[1]);
1283 close(go_pipe[0]); 1329 close(go_pipe[0]);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index e0868a901c4a..d1ecde0fd56c 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -15,6 +15,7 @@
15#include <linux/perf_event.h> 15#include <linux/perf_event.h>
16#include <sys/resource.h> 16#include <sys/resource.h>
17#include "asm/bug.h" 17#include "asm/bug.h"
18#include "callchain.h"
18#include "evsel.h" 19#include "evsel.h"
19#include "evlist.h" 20#include "evlist.h"
20#include "util.h" 21#include "util.h"
@@ -32,6 +33,48 @@ static struct {
32 bool cloexec; 33 bool cloexec;
33} perf_missing_features; 34} perf_missing_features;
34 35
36static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused)
37{
38 return 0;
39}
40
41static void perf_evsel__no_extra_fini(struct perf_evsel *evsel __maybe_unused)
42{
43}
44
45static struct {
46 size_t size;
47 int (*init)(struct perf_evsel *evsel);
48 void (*fini)(struct perf_evsel *evsel);
49} perf_evsel__object = {
50 .size = sizeof(struct perf_evsel),
51 .init = perf_evsel__no_extra_init,
52 .fini = perf_evsel__no_extra_fini,
53};
54
55int perf_evsel__object_config(size_t object_size,
56 int (*init)(struct perf_evsel *evsel),
57 void (*fini)(struct perf_evsel *evsel))
58{
59
60 if (object_size == 0)
61 goto set_methods;
62
63 if (perf_evsel__object.size > object_size)
64 return -EINVAL;
65
66 perf_evsel__object.size = object_size;
67
68set_methods:
69 if (init != NULL)
70 perf_evsel__object.init = init;
71
72 if (fini != NULL)
73 perf_evsel__object.fini = fini;
74
75 return 0;
76}
77
35#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 78#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
36 79
37int __perf_evsel__sample_size(u64 sample_type) 80int __perf_evsel__sample_size(u64 sample_type)
@@ -116,16 +159,6 @@ void perf_evsel__calc_id_pos(struct perf_evsel *evsel)
116 evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type); 159 evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type);
117} 160}
118 161
119void hists__init(struct hists *hists)
120{
121 memset(hists, 0, sizeof(*hists));
122 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
123 hists->entries_in = &hists->entries_in_array[0];
124 hists->entries_collapsed = RB_ROOT;
125 hists->entries = RB_ROOT;
126 pthread_mutex_init(&hists->lock, NULL);
127}
128
129void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, 162void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
130 enum perf_event_sample_format bit) 163 enum perf_event_sample_format bit)
131{ 164{
@@ -168,14 +201,14 @@ void perf_evsel__init(struct perf_evsel *evsel,
168 evsel->unit = ""; 201 evsel->unit = "";
169 evsel->scale = 1.0; 202 evsel->scale = 1.0;
170 INIT_LIST_HEAD(&evsel->node); 203 INIT_LIST_HEAD(&evsel->node);
171 hists__init(&evsel->hists); 204 perf_evsel__object.init(evsel);
172 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 205 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
173 perf_evsel__calc_id_pos(evsel); 206 perf_evsel__calc_id_pos(evsel);
174} 207}
175 208
176struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) 209struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
177{ 210{
178 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 211 struct perf_evsel *evsel = zalloc(perf_evsel__object.size);
179 212
180 if (evsel != NULL) 213 if (evsel != NULL)
181 perf_evsel__init(evsel, attr, idx); 214 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 218
186struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) 219struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
187{ 220{
188 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 221 struct perf_evsel *evsel = zalloc(perf_evsel__object.size);
189 222
190 if (evsel != NULL) { 223 if (evsel != NULL) {
191 struct perf_event_attr attr = { 224 struct perf_event_attr attr = {
@@ -692,7 +725,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
692 } 725 }
693} 726}
694 727
695int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 728static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
696{ 729{
697 int cpu, thread; 730 int cpu, thread;
698 731
@@ -780,13 +813,13 @@ int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
780 return evsel->counts != NULL ? 0 : -ENOMEM; 813 return evsel->counts != NULL ? 0 : -ENOMEM;
781} 814}
782 815
783void perf_evsel__free_fd(struct perf_evsel *evsel) 816static void perf_evsel__free_fd(struct perf_evsel *evsel)
784{ 817{
785 xyarray__delete(evsel->fd); 818 xyarray__delete(evsel->fd);
786 evsel->fd = NULL; 819 evsel->fd = NULL;
787} 820}
788 821
789void perf_evsel__free_id(struct perf_evsel *evsel) 822static void perf_evsel__free_id(struct perf_evsel *evsel)
790{ 823{
791 xyarray__delete(evsel->sample_id); 824 xyarray__delete(evsel->sample_id);
792 evsel->sample_id = NULL; 825 evsel->sample_id = NULL;
@@ -817,6 +850,7 @@ void perf_evsel__exit(struct perf_evsel *evsel)
817 assert(list_empty(&evsel->node)); 850 assert(list_empty(&evsel->node));
818 perf_evsel__free_fd(evsel); 851 perf_evsel__free_fd(evsel);
819 perf_evsel__free_id(evsel); 852 perf_evsel__free_id(evsel);
853 perf_evsel__object.fini(evsel);
820} 854}
821 855
822void perf_evsel__delete(struct perf_evsel *evsel) 856void perf_evsel__delete(struct perf_evsel *evsel)
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 7bc314be6a7b..1d5c754aebc4 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -8,7 +8,6 @@
8#include <linux/types.h> 8#include <linux/types.h>
9#include "xyarray.h" 9#include "xyarray.h"
10#include "cgroup.h" 10#include "cgroup.h"
11#include "hist.h"
12#include "symbol.h" 11#include "symbol.h"
13 12
14struct perf_counts_values { 13struct perf_counts_values {
@@ -66,7 +65,6 @@ struct perf_evsel {
66 struct perf_counts *prev_raw_counts; 65 struct perf_counts *prev_raw_counts;
67 int idx; 66 int idx;
68 u32 ids; 67 u32 ids;
69 struct hists hists;
70 char *name; 68 char *name;
71 double scale; 69 double scale;
72 const char *unit; 70 const char *unit;
@@ -100,13 +98,16 @@ union u64_swap {
100 u32 val32[2]; 98 u32 val32[2];
101}; 99};
102 100
103#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
104
105struct cpu_map; 101struct cpu_map;
102struct target;
106struct thread_map; 103struct thread_map;
107struct perf_evlist; 104struct perf_evlist;
108struct record_opts; 105struct record_opts;
109 106
107int perf_evsel__object_config(size_t object_size,
108 int (*init)(struct perf_evsel *evsel),
109 void (*fini)(struct perf_evsel *evsel));
110
110struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); 111struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx);
111 112
112static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) 113static 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);
153const char *perf_evsel__group_name(struct perf_evsel *evsel); 154const char *perf_evsel__group_name(struct perf_evsel *evsel);
154int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); 155int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
155 156
156int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
157int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 157int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
158int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 158int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
159void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); 159void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
160void perf_evsel__free_fd(struct perf_evsel *evsel);
161void perf_evsel__free_id(struct perf_evsel *evsel);
162void perf_evsel__free_counts(struct perf_evsel *evsel); 160void perf_evsel__free_counts(struct perf_evsel *evsel);
163void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 161void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
164 162
@@ -281,8 +279,6 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
281 return __perf_evsel__read(evsel, ncpus, nthreads, true); 279 return __perf_evsel__read(evsel, ncpus, nthreads, true);
282} 280}
283 281
284void hists__init(struct hists *hists);
285
286int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, 282int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
287 struct perf_sample *sample); 283 struct perf_sample *sample);
288 284
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 86569fa3651d..6e88b9e395df 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -3,6 +3,7 @@
3#include "hist.h" 3#include "hist.h"
4#include "session.h" 4#include "session.h"
5#include "sort.h" 5#include "sort.h"
6#include "evlist.h"
6#include "evsel.h" 7#include "evsel.h"
7#include "annotate.h" 8#include "annotate.h"
8#include <math.h> 9#include <math.h>
@@ -14,13 +15,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
14static bool hists__filter_entry_by_symbol(struct hists *hists, 15static bool hists__filter_entry_by_symbol(struct hists *hists,
15 struct hist_entry *he); 16 struct hist_entry *he);
16 17
17struct callchain_param callchain_param = {
18 .mode = CHAIN_GRAPH_REL,
19 .min_percent = 0.5,
20 .order = ORDER_CALLEE,
21 .key = CCKEY_FUNCTION
22};
23
24u16 hists__col_len(struct hists *hists, enum hist_column col) 18u16 hists__col_len(struct hists *hists, enum hist_column col)
25{ 19{
26 return hists->col_len[col]; 20 return hists->col_len[col];
@@ -516,6 +510,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
516{ 510{
517 u64 cost; 511 u64 cost;
518 struct mem_info *mi = iter->priv; 512 struct mem_info *mi = iter->priv;
513 struct hists *hists = evsel__hists(iter->evsel);
519 struct hist_entry *he; 514 struct hist_entry *he;
520 515
521 if (mi == NULL) 516 if (mi == NULL)
@@ -532,7 +527,7 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
532 * and this is indirectly achieved by passing period=weight here 527 * and this is indirectly achieved by passing period=weight here
533 * and the he_stat__add_period() function. 528 * and the he_stat__add_period() function.
534 */ 529 */
535 he = __hists__add_entry(&iter->evsel->hists, al, iter->parent, NULL, mi, 530 he = __hists__add_entry(hists, al, iter->parent, NULL, mi,
536 cost, cost, 0, true); 531 cost, cost, 0, true);
537 if (!he) 532 if (!he)
538 return -ENOMEM; 533 return -ENOMEM;
@@ -546,13 +541,14 @@ iter_finish_mem_entry(struct hist_entry_iter *iter,
546 struct addr_location *al __maybe_unused) 541 struct addr_location *al __maybe_unused)
547{ 542{
548 struct perf_evsel *evsel = iter->evsel; 543 struct perf_evsel *evsel = iter->evsel;
544 struct hists *hists = evsel__hists(evsel);
549 struct hist_entry *he = iter->he; 545 struct hist_entry *he = iter->he;
550 int err = -EINVAL; 546 int err = -EINVAL;
551 547
552 if (he == NULL) 548 if (he == NULL)
553 goto out; 549 goto out;
554 550
555 hists__inc_nr_samples(&evsel->hists, he->filtered); 551 hists__inc_nr_samples(hists, he->filtered);
556 552
557 err = hist_entry__append_callchain(he, iter->sample); 553 err = hist_entry__append_callchain(he, iter->sample);
558 554
@@ -618,6 +614,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
618{ 614{
619 struct branch_info *bi; 615 struct branch_info *bi;
620 struct perf_evsel *evsel = iter->evsel; 616 struct perf_evsel *evsel = iter->evsel;
617 struct hists *hists = evsel__hists(evsel);
621 struct hist_entry *he = NULL; 618 struct hist_entry *he = NULL;
622 int i = iter->curr; 619 int i = iter->curr;
623 int err = 0; 620 int err = 0;
@@ -631,12 +628,12 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
631 * The report shows the percentage of total branches captured 628 * The report shows the percentage of total branches captured
632 * and not events sampled. Thus we use a pseudo period of 1. 629 * and not events sampled. Thus we use a pseudo period of 1.
633 */ 630 */
634 he = __hists__add_entry(&evsel->hists, al, iter->parent, &bi[i], NULL, 631 he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
635 1, 1, 0, true); 632 1, 1, 0, true);
636 if (he == NULL) 633 if (he == NULL)
637 return -ENOMEM; 634 return -ENOMEM;
638 635
639 hists__inc_nr_samples(&evsel->hists, he->filtered); 636 hists__inc_nr_samples(hists, he->filtered);
640 637
641out: 638out:
642 iter->he = he; 639 iter->he = he;
@@ -668,7 +665,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
668 struct perf_sample *sample = iter->sample; 665 struct perf_sample *sample = iter->sample;
669 struct hist_entry *he; 666 struct hist_entry *he;
670 667
671 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, 668 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
672 sample->period, sample->weight, 669 sample->period, sample->weight,
673 sample->transaction, true); 670 sample->transaction, true);
674 if (he == NULL) 671 if (he == NULL)
@@ -691,7 +688,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter,
691 688
692 iter->he = NULL; 689 iter->he = NULL;
693 690
694 hists__inc_nr_samples(&evsel->hists, he->filtered); 691 hists__inc_nr_samples(evsel__hists(evsel), he->filtered);
695 692
696 return hist_entry__append_callchain(he, sample); 693 return hist_entry__append_callchain(he, sample);
697} 694}
@@ -724,12 +721,13 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
724 struct addr_location *al) 721 struct addr_location *al)
725{ 722{
726 struct perf_evsel *evsel = iter->evsel; 723 struct perf_evsel *evsel = iter->evsel;
724 struct hists *hists = evsel__hists(evsel);
727 struct perf_sample *sample = iter->sample; 725 struct perf_sample *sample = iter->sample;
728 struct hist_entry **he_cache = iter->priv; 726 struct hist_entry **he_cache = iter->priv;
729 struct hist_entry *he; 727 struct hist_entry *he;
730 int err = 0; 728 int err = 0;
731 729
732 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, 730 he = __hists__add_entry(hists, al, iter->parent, NULL, NULL,
733 sample->period, sample->weight, 731 sample->period, sample->weight,
734 sample->transaction, true); 732 sample->transaction, true);
735 if (he == NULL) 733 if (he == NULL)
@@ -746,7 +744,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
746 */ 744 */
747 callchain_cursor_commit(&callchain_cursor); 745 callchain_cursor_commit(&callchain_cursor);
748 746
749 hists__inc_nr_samples(&evsel->hists, he->filtered); 747 hists__inc_nr_samples(hists, he->filtered);
750 748
751 return err; 749 return err;
752} 750}
@@ -802,7 +800,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
802 } 800 }
803 } 801 }
804 802
805 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL, 803 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
806 sample->period, sample->weight, 804 sample->period, sample->weight,
807 sample->transaction, false); 805 sample->transaction, false);
808 if (he == NULL) 806 if (he == NULL)
@@ -1408,6 +1406,21 @@ int hists__link(struct hists *leader, struct hists *other)
1408 return 0; 1406 return 0;
1409} 1407}
1410 1408
1409
1410size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp)
1411{
1412 struct perf_evsel *pos;
1413 size_t ret = 0;
1414
1415 evlist__for_each(evlist, pos) {
1416 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1417 ret += events_stats__fprintf(&evsel__hists(pos)->stats, fp);
1418 }
1419
1420 return ret;
1421}
1422
1423
1411u64 hists__total_period(struct hists *hists) 1424u64 hists__total_period(struct hists *hists)
1412{ 1425{
1413 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period : 1426 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 1447
1435 return 0; 1448 return 0;
1436} 1449}
1450
1451static int hists_evsel__init(struct perf_evsel *evsel)
1452{
1453 struct hists *hists = evsel__hists(evsel);
1454
1455 memset(hists, 0, sizeof(*hists));
1456 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
1457 hists->entries_in = &hists->entries_in_array[0];
1458 hists->entries_collapsed = RB_ROOT;
1459 hists->entries = RB_ROOT;
1460 pthread_mutex_init(&hists->lock, NULL);
1461 return 0;
1462}
1463
1464/*
1465 * XXX We probably need a hists_evsel__exit() to free the hist_entries
1466 * stored in the rbtree...
1467 */
1468
1469int hists__init(void)
1470{
1471 int err = perf_evsel__object_config(sizeof(struct hists_evsel),
1472 hists_evsel__init, NULL);
1473 if (err)
1474 fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
1475
1476 return err;
1477}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8c9c70e18cbb..d0ef9a19a744 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -4,12 +4,11 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include <pthread.h> 5#include <pthread.h>
6#include "callchain.h" 6#include "callchain.h"
7#include "evsel.h"
7#include "header.h" 8#include "header.h"
8#include "color.h" 9#include "color.h"
9#include "ui/progress.h" 10#include "ui/progress.h"
10 11
11extern struct callchain_param callchain_param;
12
13struct hist_entry; 12struct hist_entry;
14struct addr_location; 13struct addr_location;
15struct symbol; 14struct symbol;
@@ -23,32 +22,6 @@ enum hist_filter {
23 HIST_FILTER__HOST, 22 HIST_FILTER__HOST,
24}; 23};
25 24
26/*
27 * The kernel collects the number of events it couldn't send in a stretch and
28 * when possible sends this number in a PERF_RECORD_LOST event. The number of
29 * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while
30 * total_lost tells exactly how many events the kernel in fact lost, i.e. it is
31 * the sum of all struct lost_event.lost fields reported.
32 *
33 * The total_period is needed because by default auto-freq is used, so
34 * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get
35 * the total number of low level events, it is necessary to to sum all struct
36 * sample_event.period and stash the result in total_period.
37 */
38struct events_stats {
39 u64 total_period;
40 u64 total_non_filtered_period;
41 u64 total_lost;
42 u64 total_invalid_chains;
43 u32 nr_events[PERF_RECORD_HEADER_MAX];
44 u32 nr_non_filtered_samples;
45 u32 nr_lost_warned;
46 u32 nr_unknown_events;
47 u32 nr_invalid_chains;
48 u32 nr_unknown_id;
49 u32 nr_unprocessable_samples;
50};
51
52enum hist_column { 25enum hist_column {
53 HISTC_SYMBOL, 26 HISTC_SYMBOL,
54 HISTC_DSO, 27 HISTC_DSO,
@@ -165,6 +138,7 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
165 138
166size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 139size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
167 int max_cols, float min_pcnt, FILE *fp); 140 int max_cols, float min_pcnt, FILE *fp);
141size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp);
168 142
169void hists__filter_by_dso(struct hists *hists); 143void hists__filter_by_dso(struct hists *hists);
170void hists__filter_by_thread(struct hists *hists); 144void hists__filter_by_thread(struct hists *hists);
@@ -185,6 +159,25 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
185void hists__match(struct hists *leader, struct hists *other); 159void hists__match(struct hists *leader, struct hists *other);
186int hists__link(struct hists *leader, struct hists *other); 160int hists__link(struct hists *leader, struct hists *other);
187 161
162struct hists_evsel {
163 struct perf_evsel evsel;
164 struct hists hists;
165};
166
167static inline struct perf_evsel *hists_to_evsel(struct hists *hists)
168{
169 struct hists_evsel *hevsel = container_of(hists, struct hists_evsel, hists);
170 return &hevsel->evsel;
171}
172
173static inline struct hists *evsel__hists(struct perf_evsel *evsel)
174{
175 struct hists_evsel *hevsel = (struct hists_evsel *)evsel;
176 return &hevsel->hists;
177}
178
179int hists__init(void);
180
188struct perf_hpp { 181struct perf_hpp {
189 char *buf; 182 char *buf;
190 size_t size; 183 size_t size;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index b7d477fbda02..34fc7c8672e4 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -13,12 +13,18 @@
13#include <symbol/kallsyms.h> 13#include <symbol/kallsyms.h>
14#include "unwind.h" 14#include "unwind.h"
15 15
16static void dsos__init(struct dsos *dsos)
17{
18 INIT_LIST_HEAD(&dsos->head);
19 dsos->root = RB_ROOT;
20}
21
16int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 22int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
17{ 23{
18 map_groups__init(&machine->kmaps); 24 map_groups__init(&machine->kmaps);
19 RB_CLEAR_NODE(&machine->rb_node); 25 RB_CLEAR_NODE(&machine->rb_node);
20 INIT_LIST_HEAD(&machine->user_dsos.head); 26 dsos__init(&machine->user_dsos);
21 INIT_LIST_HEAD(&machine->kernel_dsos.head); 27 dsos__init(&machine->kernel_dsos);
22 28
23 machine->threads = RB_ROOT; 29 machine->threads = RB_ROOT;
24 INIT_LIST_HEAD(&machine->dead_threads); 30 INIT_LIST_HEAD(&machine->dead_threads);
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index b7090596ac50..2137c4596ec7 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -556,7 +556,7 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
556 556
557int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) 557int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
558{ 558{
559 if (ams->addr < ams->map->start || ams->addr > ams->map->end) { 559 if (ams->addr < ams->map->start || ams->addr >= ams->map->end) {
560 if (ams->map->groups == NULL) 560 if (ams->map->groups == NULL)
561 return -1; 561 return -1;
562 ams->map = map_groups__find(ams->map->groups, ams->map->type, 562 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 goto move_map; 664 goto move_map;
665 } 665 }
666 666
667 before->end = map->start - 1; 667 before->end = map->start;
668 map_groups__insert(mg, before); 668 map_groups__insert(mg, before);
669 if (verbose >= 2) 669 if (verbose >= 2)
670 map__fprintf(before, fp); 670 map__fprintf(before, fp);
@@ -678,7 +678,7 @@ int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
678 goto move_map; 678 goto move_map;
679 } 679 }
680 680
681 after->start = map->end + 1; 681 after->start = map->end;
682 map_groups__insert(mg, after); 682 map_groups__insert(mg, after);
683 if (verbose >= 2) 683 if (verbose >= 2)
684 map__fprintf(after, fp); 684 map__fprintf(after, fp);
@@ -752,7 +752,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
752 m = rb_entry(parent, struct map, rb_node); 752 m = rb_entry(parent, struct map, rb_node);
753 if (ip < m->start) 753 if (ip < m->start)
754 p = &(*p)->rb_left; 754 p = &(*p)->rb_left;
755 else if (ip > m->end) 755 else if (ip >= m->end)
756 p = &(*p)->rb_right; 756 p = &(*p)->rb_right;
757 else 757 else
758 return m; 758 return m;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 56ba07cce549..496f21cadd97 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -28,6 +28,7 @@
28 28
29#include "../../perf.h" 29#include "../../perf.h"
30#include "../debug.h" 30#include "../debug.h"
31#include "../callchain.h"
31#include "../evsel.h" 32#include "../evsel.h"
32#include "../util.h" 33#include "../util.h"
33#include "../event.h" 34#include "../event.h"
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 883406f4b381..896bac73ea08 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -813,22 +813,6 @@ int perf_session__deliver_event(struct perf_session *session,
813 dump_event(session, event, file_offset, sample); 813 dump_event(session, event, file_offset, sample);
814 814
815 evsel = perf_evlist__id2evsel(session->evlist, sample->id); 815 evsel = perf_evlist__id2evsel(session->evlist, sample->id);
816 if (evsel != NULL && event->header.type != PERF_RECORD_SAMPLE) {
817 /*
818 * XXX We're leaving PERF_RECORD_SAMPLE unnacounted here
819 * because the tools right now may apply filters, discarding
820 * some of the samples. For consistency, in the future we
821 * should have something like nr_filtered_samples and remove
822 * the sample->period from total_sample_period, etc, KISS for
823 * now tho.
824 *
825 * Also testing against NULL allows us to handle files without
826 * attr.sample_id_all and/or without PERF_SAMPLE_ID. In the
827 * future probably it'll be a good idea to restrict event
828 * processing via perf_session to files with both set.
829 */
830 hists__inc_nr_events(&evsel->hists, event->header.type);
831 }
832 816
833 machine = perf_session__find_machine_for_cpumode(session, event, 817 machine = perf_session__find_machine_for_cpumode(session, event,
834 sample); 818 sample);
@@ -1391,16 +1375,9 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp
1391 1375
1392size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1376size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
1393{ 1377{
1394 struct perf_evsel *pos;
1395 size_t ret = fprintf(fp, "Aggregated stats:\n"); 1378 size_t ret = fprintf(fp, "Aggregated stats:\n");
1396 1379
1397 ret += events_stats__fprintf(&session->stats, fp); 1380 ret += events_stats__fprintf(&session->stats, fp);
1398
1399 evlist__for_each(session->evlist, pos) {
1400 ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
1401 ret += events_stats__fprintf(&pos->hists.stats, fp);
1402 }
1403
1404 return ret; 1381 return ret;
1405} 1382}
1406 1383
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index ffb440462008..a4be851f1a90 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -2,7 +2,6 @@
2#define __PERF_SESSION_H 2#define __PERF_SESSION_H
3 3
4#include "trace-event.h" 4#include "trace-event.h"
5#include "hist.h"
6#include "event.h" 5#include "event.h"
7#include "header.h" 6#include "header.h"
8#include "machine.h" 7#include "machine.h"
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 289df9d1e65a..4906cd81cb56 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1218,7 +1218,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1218 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1218 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1219 1219
1220 if (!len) 1220 if (!len)
1221 len = hists__col_len(&evsel->hists, hse->se->se_width_idx); 1221 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
1222 1222
1223 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); 1223 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
1224} 1224}
@@ -1233,7 +1233,7 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1233 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1233 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1234 1234
1235 if (!len) 1235 if (!len)
1236 len = hists__col_len(&evsel->hists, hse->se->se_width_idx); 1236 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
1237 1237
1238 return len; 1238 return len;
1239} 1239}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index be84f7a9838b..078331140d8c 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -186,7 +186,7 @@ void symbols__fixup_end(struct rb_root *symbols)
186 curr = rb_entry(nd, struct symbol, rb_node); 186 curr = rb_entry(nd, struct symbol, rb_node);
187 187
188 if (prev->end == prev->start && prev->end != curr->start) 188 if (prev->end == prev->start && prev->end != curr->start)
189 prev->end = curr->start - 1; 189 prev->end = curr->start;
190 } 190 }
191 191
192 /* Last entry */ 192 /* Last entry */
@@ -207,7 +207,7 @@ void __map_groups__fixup_end(struct map_groups *mg, enum map_type type)
207 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 207 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
208 prev = curr; 208 prev = curr;
209 curr = rb_entry(nd, struct map, rb_node); 209 curr = rb_entry(nd, struct map, rb_node);
210 prev->end = curr->start - 1; 210 prev->end = curr->start;
211 } 211 }
212 212
213 /* 213 /*
@@ -229,7 +229,7 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
229 sym = ((void *)sym) + symbol_conf.priv_size; 229 sym = ((void *)sym) + symbol_conf.priv_size;
230 230
231 sym->start = start; 231 sym->start = start;
232 sym->end = len ? start + len - 1 : start; 232 sym->end = len ? start + len : start;
233 sym->binding = binding; 233 sym->binding = binding;
234 sym->namelen = namelen - 1; 234 sym->namelen = namelen - 1;
235 235
@@ -325,7 +325,7 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip)
325 325
326 if (ip < s->start) 326 if (ip < s->start)
327 n = n->rb_left; 327 n = n->rb_left;
328 else if (ip > s->end) 328 else if (ip >= s->end)
329 n = n->rb_right; 329 n = n->rb_right;
330 else 330 else
331 return s; 331 return s;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index bec4b7bd09de..eb2c19bf8d90 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -95,7 +95,7 @@ void symbols__delete(struct rb_root *symbols);
95 95
96static inline size_t symbol__size(const struct symbol *sym) 96static inline size_t symbol__size(const struct symbol *sym)
97{ 97{
98 return sym->end - sym->start + 1; 98 return sym->end - sym->start;
99} 99}
100 100
101struct strlist; 101struct strlist;
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 5d3215912105..f93b9734735b 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -214,6 +214,17 @@ out_free_threads:
214 goto out; 214 goto out;
215} 215}
216 216
217struct thread_map *thread_map__new_dummy(void)
218{
219 struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t));
220
221 if (threads != NULL) {
222 threads->map[0] = -1;
223 threads->nr = 1;
224 }
225 return threads;
226}
227
217static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) 228static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
218{ 229{
219 struct thread_map *threads = NULL, *nt; 230 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 struct strlist *slist; 235 struct strlist *slist;
225 236
226 /* perf-stat expects threads to be generated even if tid not given */ 237 /* perf-stat expects threads to be generated even if tid not given */
227 if (!tid_str) { 238 if (!tid_str)
228 threads = malloc(sizeof(*threads) + sizeof(pid_t)); 239 return thread_map__new_dummy();
229 if (threads != NULL) {
230 threads->map[0] = -1;
231 threads->nr = 1;
232 }
233 return threads;
234 }
235 240
236 slist = strlist__new(false, tid_str); 241 slist = strlist__new(false, tid_str);
237 if (!slist) 242 if (!slist)
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 0cd8b3108084..95313f43cc0f 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -9,6 +9,7 @@ struct thread_map {
9 pid_t map[]; 9 pid_t map[];
10}; 10};
11 11
12struct thread_map *thread_map__new_dummy(void);
12struct thread_map *thread_map__new_by_pid(pid_t pid); 13struct thread_map *thread_map__new_by_pid(pid_t pid);
13struct thread_map *thread_map__new_by_tid(pid_t tid); 14struct thread_map *thread_map__new_by_tid(pid_t tid);
14struct thread_map *thread_map__new_by_uid(uid_t uid); 15struct thread_map *thread_map__new_by_uid(uid_t uid);
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 24e8d871b74e..d5eab3f3323f 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -14,6 +14,14 @@
14#include <byteswap.h> 14#include <byteswap.h>
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <unistd.h> 16#include <unistd.h>
17#include "callchain.h"
18
19struct callchain_param callchain_param = {
20 .mode = CHAIN_GRAPH_REL,
21 .min_percent = 0.5,
22 .order = ORDER_CALLEE,
23 .key = CCKEY_FUNCTION
24};
17 25
18/* 26/*
19 * XXX We need to find a better place for these things... 27 * XXX We need to find a better place for these things...