diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-10-15 05:54:14 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-10-15 05:54:14 -0400 |
commit | ec4212d88a77eb6caec10777ddd629b702a5ebbd (patch) | |
tree | 03b4b08df9d633e15df8c0ff27444324adf4a312 /tools | |
parent | 77654908ff1a58cee4886298968b5262884aff0b (diff) | |
parent | 2c241bd35e6f626ad6f867dcf9fefdc2315f125f (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
Infrastructure fixes and changes:
* Fix off-by-one bugs in map->end handling (Stephane Eranian)
* Fix off-by-one bug in maps__find(), also related to map->end handling (Namhyung Kim)
* Make struct symbol->end be the first addr after the symbol range, to make it
match the convention used for struct map->end. (Arnaldo Carvalho de Melo)
* Fix perf_evlist__add_pollfd() error handling in 'perf kvm stat live' (Jiri Olsa)
* Fix python test build by moving callchain_param to an object linked into the
python binding (Jiri Olsa)
* Do not include a struct hists per perf_evsel, untangling the histogram code
from perf_evsel, to pave the way for exporting a minimalistic
tools/lib/api/perf/ library usable by tools/perf and initially by the rasd
daemon being developed by Borislav Petkov, Robert Richter and Jean Pihet.
(Arnaldo Carvalho de Melo)
* Make perf_evlist__open(evlist, NULL, NULL), i.e. without cpu and thread
maps mean syswide monitoring, reducing the boilerplate for tools that
only want system wide mode. (Arnaldo Carvalho de Melo)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
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 | ||
897 | static int kvm_events_live_report(struct perf_kvm_stat *kvm) | 897 | static 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) | |||
538 | static void perf_top__sort_new_samples(void *arg) | 537 | static 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 | ||
558 | static void *display_thread_tui(void *arg) | 560 | static 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 | ||
1043 | int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | 1048 | int 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 | |||
245 | static int test1(struct perf_evsel *evsel, struct machine *machine) | 245 | static 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: | |||
295 | static int test2(struct perf_evsel *evsel, struct machine *machine) | 295 | static 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: | |||
442 | static int test3(struct perf_evsel *evsel, struct machine *machine) | 442 | static 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: | |||
498 | static int test4(struct perf_evsel *evsel, struct machine *machine) | 498 | static 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) | |||
271 | int test__hists_link(void) | 273 | int 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 *); | |||
122 | static int test1(struct perf_evsel *evsel, struct machine *machine) | 122 | static 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: | |||
224 | static int test2(struct perf_evsel *evsel, struct machine *machine) | 224 | static 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: | |||
280 | static int test3(struct perf_evsel *evsel, struct machine *machine) | 280 | static 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: | |||
354 | static int test4(struct perf_evsel *evsel, struct machine *machine) | 354 | static 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: | |||
456 | static int test5(struct perf_evsel *evsel, struct machine *machine) | 456 | static 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 | ||
68 | extern struct callchain_param callchain_param; | ||
69 | |||
68 | struct callchain_list { | 70 | struct 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 | */ | ||
205 | struct 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 | |||
193 | struct attr_event { | 219 | struct 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 | ||
1178 | static 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; | ||
1200 | out: | ||
1201 | return err; | ||
1202 | out_free_cpus: | ||
1203 | cpu_map__delete(evlist->cpus); | ||
1204 | evlist->cpus = NULL; | ||
1205 | goto out; | ||
1206 | } | ||
1207 | |||
1178 | int perf_evlist__open(struct perf_evlist *evlist) | 1208 | int 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 | ||
36 | static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) | ||
37 | { | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void perf_evsel__no_extra_fini(struct perf_evsel *evsel __maybe_unused) | ||
42 | { | ||
43 | } | ||
44 | |||
45 | static 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 | |||
55 | int 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 | |||
68 | set_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 | ||
37 | int __perf_evsel__sample_size(u64 sample_type) | 80 | int __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 | ||
119 | void 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 | |||
129 | void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, | 162 | void __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 | ||
176 | struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) | 209 | struct 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 | ||
186 | struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) | 219 | struct 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 | ||
695 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 728 | static 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 | ||
783 | void perf_evsel__free_fd(struct perf_evsel *evsel) | 816 | static 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 | ||
789 | void perf_evsel__free_id(struct perf_evsel *evsel) | 822 | static 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 | ||
822 | void perf_evsel__delete(struct perf_evsel *evsel) | 856 | void perf_evsel__delete(struct perf_evsel *evsel) |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 7bc314be6a7b..1d5c754aebc4 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -8,7 +8,6 @@ | |||
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 | ||
14 | struct perf_counts_values { | 13 | struct 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 | |||
105 | struct cpu_map; | 101 | struct cpu_map; |
102 | struct target; | ||
106 | struct thread_map; | 103 | struct thread_map; |
107 | struct perf_evlist; | 104 | struct perf_evlist; |
108 | struct record_opts; | 105 | struct record_opts; |
109 | 106 | ||
107 | int perf_evsel__object_config(size_t object_size, | ||
108 | int (*init)(struct perf_evsel *evsel), | ||
109 | void (*fini)(struct perf_evsel *evsel)); | ||
110 | |||
110 | struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); | 111 | struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); |
111 | 112 | ||
112 | static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) | 113 | static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) |
@@ -153,12 +154,9 @@ const char *perf_evsel__name(struct perf_evsel *evsel); | |||
153 | const char *perf_evsel__group_name(struct perf_evsel *evsel); | 154 | const char *perf_evsel__group_name(struct perf_evsel *evsel); |
154 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); | 155 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); |
155 | 156 | ||
156 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | ||
157 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 157 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
158 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 158 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); |
159 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); | 159 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); |
160 | void perf_evsel__free_fd(struct perf_evsel *evsel); | ||
161 | void perf_evsel__free_id(struct perf_evsel *evsel); | ||
162 | void perf_evsel__free_counts(struct perf_evsel *evsel); | 160 | void perf_evsel__free_counts(struct perf_evsel *evsel); |
163 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 161 | void 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 | ||
284 | void hists__init(struct hists *hists); | ||
285 | |||
286 | int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | 282 | int 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, | |||
14 | static bool hists__filter_entry_by_symbol(struct hists *hists, | 15 | static bool hists__filter_entry_by_symbol(struct hists *hists, |
15 | struct hist_entry *he); | 16 | struct hist_entry *he); |
16 | 17 | ||
17 | struct callchain_param callchain_param = { | ||
18 | .mode = CHAIN_GRAPH_REL, | ||
19 | .min_percent = 0.5, | ||
20 | .order = ORDER_CALLEE, | ||
21 | .key = CCKEY_FUNCTION | ||
22 | }; | ||
23 | |||
24 | u16 hists__col_len(struct hists *hists, enum hist_column col) | 18 | u16 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 | ||
641 | out: | 638 | out: |
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 | |||
1410 | size_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 | |||
1411 | u64 hists__total_period(struct hists *hists) | 1424 | u64 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 | |||
1451 | static 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 | |||
1469 | int 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 | ||
11 | extern struct callchain_param callchain_param; | ||
12 | |||
13 | struct hist_entry; | 12 | struct hist_entry; |
14 | struct addr_location; | 13 | struct addr_location; |
15 | struct symbol; | 14 | struct 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 | */ | ||
38 | struct 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 | |||
52 | enum hist_column { | 25 | enum 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 | ||
166 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 139 | size_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); |
141 | size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); | ||
168 | 142 | ||
169 | void hists__filter_by_dso(struct hists *hists); | 143 | void hists__filter_by_dso(struct hists *hists); |
170 | void hists__filter_by_thread(struct hists *hists); | 144 | void hists__filter_by_thread(struct hists *hists); |
@@ -185,6 +159,25 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he); | |||
185 | void hists__match(struct hists *leader, struct hists *other); | 159 | void hists__match(struct hists *leader, struct hists *other); |
186 | int hists__link(struct hists *leader, struct hists *other); | 160 | int hists__link(struct hists *leader, struct hists *other); |
187 | 161 | ||
162 | struct hists_evsel { | ||
163 | struct perf_evsel evsel; | ||
164 | struct hists hists; | ||
165 | }; | ||
166 | |||
167 | static 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 | |||
173 | static 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 | |||
179 | int hists__init(void); | ||
180 | |||
188 | struct perf_hpp { | 181 | struct 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 | ||
16 | static void dsos__init(struct dsos *dsos) | ||
17 | { | ||
18 | INIT_LIST_HEAD(&dsos->head); | ||
19 | dsos->root = RB_ROOT; | ||
20 | } | ||
21 | |||
16 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 22 | int 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 | ||
557 | int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) | 557 | int 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 | ||
1392 | size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | 1376 | size_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 | ||
96 | static inline size_t symbol__size(const struct symbol *sym) | 96 | static 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 | ||
101 | struct strlist; | 101 | struct strlist; |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 5d3215912105..f93b9734735b 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -214,6 +214,17 @@ out_free_threads: | |||
214 | goto out; | 214 | goto out; |
215 | } | 215 | } |
216 | 216 | ||
217 | struct 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 | |||
217 | static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) | 228 | static 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 | ||
12 | struct thread_map *thread_map__new_dummy(void); | ||
12 | struct thread_map *thread_map__new_by_pid(pid_t pid); | 13 | struct thread_map *thread_map__new_by_pid(pid_t pid); |
13 | struct thread_map *thread_map__new_by_tid(pid_t tid); | 14 | struct thread_map *thread_map__new_by_tid(pid_t tid); |
14 | struct thread_map *thread_map__new_by_uid(uid_t uid); | 15 | struct thread_map *thread_map__new_by_uid(uid_t uid); |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 24e8d871b74e..d5eab3f3323f 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -14,6 +14,14 @@ | |||
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 | |||
19 | struct 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... |