diff options
author | Ingo Molnar <mingo@kernel.org> | 2014-04-25 04:04:46 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-04-25 04:04:46 -0400 |
commit | 2933d7813d8618f18632a7dc7f4e7f1f7d17383a (patch) | |
tree | dd178b76789c1d798c3aca230beaa7fac6872dcb | |
parent | 42ebd27bcbda7895fa07c61185a26d8379945ed0 (diff) | |
parent | c3b789527b236873557f53740ceac47747e0e1cb (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core
Pull perf/core improvements and fixes from Jiri Olsa:
* Factor hists statistics counts processing which in turn also
fixes several bugs in TUI report command (Namhyung Kim)
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/builtin-annotate.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-diff.c | 23 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 64 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 92 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 83 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 9 |
6 files changed, 171 insertions, 103 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 0da603b79b61..d30d2c2e2a7a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -46,7 +46,7 @@ struct perf_annotate { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | static int perf_evsel__add_sample(struct perf_evsel *evsel, | 48 | static int perf_evsel__add_sample(struct perf_evsel *evsel, |
49 | struct perf_sample *sample, | 49 | struct perf_sample *sample __maybe_unused, |
50 | struct addr_location *al, | 50 | struct addr_location *al, |
51 | struct perf_annotate *ann) | 51 | struct perf_annotate *ann) |
52 | { | 52 | { |
@@ -70,7 +70,6 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
70 | return -ENOMEM; | 70 | return -ENOMEM; |
71 | 71 | ||
72 | ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | 72 | ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); |
73 | evsel->hists.stats.total_period += sample->period; | ||
74 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 73 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
75 | return ret; | 74 | return ret; |
76 | } | 75 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 6ef80f22c1e2..f3b10dcf6838 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -341,11 +341,16 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, | |||
341 | return -1; | 341 | return -1; |
342 | } | 342 | } |
343 | 343 | ||
344 | if (al.filtered == 0) { | 344 | /* |
345 | evsel->hists.stats.total_non_filtered_period += sample->period; | 345 | * The total_period is updated here before going to the output |
346 | evsel->hists.nr_non_filtered_entries++; | 346 | * tree since normally only the baseline hists will call |
347 | } | 347 | * hists__output_resort() and precompute needs the total |
348 | * period in order to sort entries by percentage delta. | ||
349 | */ | ||
348 | evsel->hists.stats.total_period += sample->period; | 350 | evsel->hists.stats.total_period += sample->period; |
351 | if (!al.filtered) | ||
352 | evsel->hists.stats.total_non_filtered_period += sample->period; | ||
353 | |||
349 | return 0; | 354 | return 0; |
350 | } | 355 | } |
351 | 356 | ||
@@ -573,10 +578,7 @@ static void hists__compute_resort(struct hists *hists) | |||
573 | hists->entries = RB_ROOT; | 578 | hists->entries = RB_ROOT; |
574 | next = rb_first(root); | 579 | next = rb_first(root); |
575 | 580 | ||
576 | hists->nr_entries = 0; | 581 | hists__reset_stats(hists); |
577 | hists->nr_non_filtered_entries = 0; | ||
578 | hists->stats.total_period = 0; | ||
579 | hists->stats.total_non_filtered_period = 0; | ||
580 | hists__reset_col_len(hists); | 582 | hists__reset_col_len(hists); |
581 | 583 | ||
582 | while (next != NULL) { | 584 | while (next != NULL) { |
@@ -586,7 +588,10 @@ static void hists__compute_resort(struct hists *hists) | |||
586 | next = rb_next(&he->rb_node_in); | 588 | next = rb_next(&he->rb_node_in); |
587 | 589 | ||
588 | insert_hist_entry_by_compute(&hists->entries, he, compute); | 590 | insert_hist_entry_by_compute(&hists->entries, he, compute); |
589 | hists__inc_nr_entries(hists, he); | 591 | hists__inc_stats(hists, he); |
592 | |||
593 | if (!he->filtered) | ||
594 | hists__calc_col_len(hists, he); | ||
590 | } | 595 | } |
591 | } | 596 | } |
592 | 597 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 76e2bb6cf571..89c95289fd51 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -57,6 +57,7 @@ struct report { | |||
57 | const char *cpu_list; | 57 | const char *cpu_list; |
58 | const char *symbol_filter_str; | 58 | const char *symbol_filter_str; |
59 | float min_percent; | 59 | float min_percent; |
60 | u64 nr_entries; | ||
60 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 61 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
61 | }; | 62 | }; |
62 | 63 | ||
@@ -75,6 +76,27 @@ static int report__config(const char *var, const char *value, void *cb) | |||
75 | return perf_default_config(var, value, cb); | 76 | return perf_default_config(var, value, cb); |
76 | } | 77 | } |
77 | 78 | ||
79 | static void report__inc_stats(struct report *rep, struct hist_entry *he) | ||
80 | { | ||
81 | /* | ||
82 | * The @he is either of a newly created one or an existing one | ||
83 | * merging current sample. We only want to count a new one so | ||
84 | * checking ->nr_events being 1. | ||
85 | */ | ||
86 | if (he->stat.nr_events == 1) | ||
87 | rep->nr_entries++; | ||
88 | |||
89 | /* | ||
90 | * Only counts number of samples at this stage as it's more | ||
91 | * natural to do it here and non-sample events are also | ||
92 | * counted in perf_session_deliver_event(). The dump_trace | ||
93 | * requires this info is ready before going to the output tree. | ||
94 | */ | ||
95 | hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE); | ||
96 | if (!he->filtered) | ||
97 | he->hists->stats.nr_non_filtered_samples++; | ||
98 | } | ||
99 | |||
78 | static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al, | 100 | static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al, |
79 | struct perf_sample *sample, struct perf_evsel *evsel) | 101 | struct perf_sample *sample, struct perf_evsel *evsel) |
80 | { | 102 | { |
@@ -121,10 +143,8 @@ static int report__add_mem_hist_entry(struct report *rep, struct addr_location * | |||
121 | goto out; | 143 | goto out; |
122 | } | 144 | } |
123 | 145 | ||
124 | evsel->hists.stats.total_period += cost; | 146 | report__inc_stats(rep, he); |
125 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 147 | |
126 | if (!he->filtered) | ||
127 | evsel->hists.stats.nr_non_filtered_samples++; | ||
128 | err = hist_entry__append_callchain(he, sample); | 148 | err = hist_entry__append_callchain(he, sample); |
129 | out: | 149 | out: |
130 | return err; | 150 | return err; |
@@ -175,11 +195,7 @@ static int report__add_branch_hist_entry(struct report *rep, struct addr_locatio | |||
175 | if (err) | 195 | if (err) |
176 | goto out; | 196 | goto out; |
177 | } | 197 | } |
178 | 198 | report__inc_stats(rep, he); | |
179 | evsel->hists.stats.total_period += 1; | ||
180 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | ||
181 | if (!he->filtered) | ||
182 | evsel->hists.stats.nr_non_filtered_samples++; | ||
183 | } else | 199 | } else |
184 | goto out; | 200 | goto out; |
185 | } | 201 | } |
@@ -212,10 +228,8 @@ static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel, | |||
212 | if (ui__has_annotation()) | 228 | if (ui__has_annotation()) |
213 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | 229 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); |
214 | 230 | ||
215 | evsel->hists.stats.total_period += sample->period; | 231 | report__inc_stats(rep, he); |
216 | if (!he->filtered) | 232 | |
217 | evsel->hists.stats.nr_non_filtered_samples++; | ||
218 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | ||
219 | out: | 233 | out: |
220 | return err; | 234 | return err; |
221 | } | 235 | } |
@@ -486,24 +500,12 @@ static int report__browse_hists(struct report *rep) | |||
486 | return ret; | 500 | return ret; |
487 | } | 501 | } |
488 | 502 | ||
489 | static u64 report__collapse_hists(struct report *rep) | 503 | static void report__collapse_hists(struct report *rep) |
490 | { | 504 | { |
491 | struct ui_progress prog; | 505 | struct ui_progress prog; |
492 | struct perf_evsel *pos; | 506 | struct perf_evsel *pos; |
493 | u64 nr_samples = 0; | ||
494 | /* | ||
495 | * Count number of histogram entries to use when showing progress, | ||
496 | * reusing nr_samples variable. | ||
497 | */ | ||
498 | evlist__for_each(rep->session->evlist, pos) | ||
499 | nr_samples += pos->hists.nr_entries; | ||
500 | 507 | ||
501 | ui_progress__init(&prog, nr_samples, "Merging related events..."); | 508 | ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); |
502 | /* | ||
503 | * Count total number of samples, will be used to check if this | ||
504 | * session had any. | ||
505 | */ | ||
506 | nr_samples = 0; | ||
507 | 509 | ||
508 | evlist__for_each(rep->session->evlist, pos) { | 510 | evlist__for_each(rep->session->evlist, pos) { |
509 | struct hists *hists = &pos->hists; | 511 | struct hists *hists = &pos->hists; |
@@ -512,7 +514,6 @@ static u64 report__collapse_hists(struct report *rep) | |||
512 | hists->symbol_filter_str = rep->symbol_filter_str; | 514 | hists->symbol_filter_str = rep->symbol_filter_str; |
513 | 515 | ||
514 | hists__collapse_resort(hists, &prog); | 516 | hists__collapse_resort(hists, &prog); |
515 | nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; | ||
516 | 517 | ||
517 | /* Non-group events are considered as leader */ | 518 | /* Non-group events are considered as leader */ |
518 | if (symbol_conf.event_group && | 519 | if (symbol_conf.event_group && |
@@ -525,14 +526,11 @@ static u64 report__collapse_hists(struct report *rep) | |||
525 | } | 526 | } |
526 | 527 | ||
527 | ui_progress__finish(); | 528 | ui_progress__finish(); |
528 | |||
529 | return nr_samples; | ||
530 | } | 529 | } |
531 | 530 | ||
532 | static int __cmd_report(struct report *rep) | 531 | static int __cmd_report(struct report *rep) |
533 | { | 532 | { |
534 | int ret; | 533 | int ret; |
535 | u64 nr_samples; | ||
536 | struct perf_session *session = rep->session; | 534 | struct perf_session *session = rep->session; |
537 | struct perf_evsel *pos; | 535 | struct perf_evsel *pos; |
538 | struct perf_data_file *file = session->file; | 536 | struct perf_data_file *file = session->file; |
@@ -572,12 +570,12 @@ static int __cmd_report(struct report *rep) | |||
572 | } | 570 | } |
573 | } | 571 | } |
574 | 572 | ||
575 | nr_samples = report__collapse_hists(rep); | 573 | report__collapse_hists(rep); |
576 | 574 | ||
577 | if (session_done()) | 575 | if (session_done()) |
578 | return 0; | 576 | return 0; |
579 | 577 | ||
580 | if (nr_samples == 0) { | 578 | if (rep->nr_entries == 0) { |
581 | ui__error("The %s file has no samples!\n", file->path); | 579 | ui__error("The %s file has no samples!\n", file->path); |
582 | return 0; | 580 | return 0; |
583 | } | 581 | } |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 4d416984c59d..b0861e3e50a5 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -26,13 +26,36 @@ struct hist_browser { | |||
26 | int print_seq; | 26 | int print_seq; |
27 | bool show_dso; | 27 | bool show_dso; |
28 | float min_pcnt; | 28 | float min_pcnt; |
29 | u64 nr_pcnt_entries; | 29 | u64 nr_non_filtered_entries; |
30 | u64 nr_callchain_rows; | ||
30 | }; | 31 | }; |
31 | 32 | ||
32 | extern void hist_browser__init_hpp(void); | 33 | extern void hist_browser__init_hpp(void); |
33 | 34 | ||
34 | static int hists__browser_title(struct hists *hists, char *bf, size_t size, | 35 | static int hists__browser_title(struct hists *hists, char *bf, size_t size, |
35 | const char *ev_name); | 36 | const char *ev_name); |
37 | static void hist_browser__update_nr_entries(struct hist_browser *hb); | ||
38 | |||
39 | static struct rb_node *hists__filter_entries(struct rb_node *nd, | ||
40 | struct hists *hists, | ||
41 | float min_pcnt); | ||
42 | |||
43 | static bool hist_browser__has_filter(struct hist_browser *hb) | ||
44 | { | ||
45 | return hists__has_filter(hb->hists) || hb->min_pcnt; | ||
46 | } | ||
47 | |||
48 | static u32 hist_browser__nr_entries(struct hist_browser *hb) | ||
49 | { | ||
50 | u32 nr_entries; | ||
51 | |||
52 | if (hist_browser__has_filter(hb)) | ||
53 | nr_entries = hb->nr_non_filtered_entries; | ||
54 | else | ||
55 | nr_entries = hb->hists->nr_entries; | ||
56 | |||
57 | return nr_entries + hb->nr_callchain_rows; | ||
58 | } | ||
36 | 59 | ||
37 | static void hist_browser__refresh_dimensions(struct hist_browser *browser) | 60 | static void hist_browser__refresh_dimensions(struct hist_browser *browser) |
38 | { | 61 | { |
@@ -43,7 +66,14 @@ static void hist_browser__refresh_dimensions(struct hist_browser *browser) | |||
43 | 66 | ||
44 | static void hist_browser__reset(struct hist_browser *browser) | 67 | static void hist_browser__reset(struct hist_browser *browser) |
45 | { | 68 | { |
46 | browser->b.nr_entries = browser->hists->nr_entries; | 69 | /* |
70 | * The hists__remove_entry_filter() already folds non-filtered | ||
71 | * entries so we can assume it has 0 callchain rows. | ||
72 | */ | ||
73 | browser->nr_callchain_rows = 0; | ||
74 | |||
75 | hist_browser__update_nr_entries(browser); | ||
76 | browser->b.nr_entries = hist_browser__nr_entries(browser); | ||
47 | hist_browser__refresh_dimensions(browser); | 77 | hist_browser__refresh_dimensions(browser); |
48 | ui_browser__reset_index(&browser->b); | 78 | ui_browser__reset_index(&browser->b); |
49 | } | 79 | } |
@@ -198,14 +228,16 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser) | |||
198 | struct hist_entry *he = browser->he_selection; | 228 | struct hist_entry *he = browser->he_selection; |
199 | 229 | ||
200 | hist_entry__init_have_children(he); | 230 | hist_entry__init_have_children(he); |
201 | browser->hists->nr_entries -= he->nr_rows; | 231 | browser->b.nr_entries -= he->nr_rows; |
232 | browser->nr_callchain_rows -= he->nr_rows; | ||
202 | 233 | ||
203 | if (he->ms.unfolded) | 234 | if (he->ms.unfolded) |
204 | he->nr_rows = callchain__count_rows(&he->sorted_chain); | 235 | he->nr_rows = callchain__count_rows(&he->sorted_chain); |
205 | else | 236 | else |
206 | he->nr_rows = 0; | 237 | he->nr_rows = 0; |
207 | browser->hists->nr_entries += he->nr_rows; | 238 | |
208 | browser->b.nr_entries = browser->hists->nr_entries; | 239 | browser->b.nr_entries += he->nr_rows; |
240 | browser->nr_callchain_rows += he->nr_rows; | ||
209 | 241 | ||
210 | return true; | 242 | return true; |
211 | } | 243 | } |
@@ -280,23 +312,27 @@ static void hist_entry__set_folding(struct hist_entry *he, bool unfold) | |||
280 | he->nr_rows = 0; | 312 | he->nr_rows = 0; |
281 | } | 313 | } |
282 | 314 | ||
283 | static void hists__set_folding(struct hists *hists, bool unfold) | 315 | static void |
316 | __hist_browser__set_folding(struct hist_browser *browser, bool unfold) | ||
284 | { | 317 | { |
285 | struct rb_node *nd; | 318 | struct rb_node *nd; |
319 | struct hists *hists = browser->hists; | ||
286 | 320 | ||
287 | hists->nr_entries = 0; | 321 | for (nd = rb_first(&hists->entries); |
288 | 322 | (nd = hists__filter_entries(nd, hists, browser->min_pcnt)) != NULL; | |
289 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | 323 | nd = rb_next(nd)) { |
290 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); | 324 | struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); |
291 | hist_entry__set_folding(he, unfold); | 325 | hist_entry__set_folding(he, unfold); |
292 | hists->nr_entries += 1 + he->nr_rows; | 326 | browser->nr_callchain_rows += he->nr_rows; |
293 | } | 327 | } |
294 | } | 328 | } |
295 | 329 | ||
296 | static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) | 330 | static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) |
297 | { | 331 | { |
298 | hists__set_folding(browser->hists, unfold); | 332 | browser->nr_callchain_rows = 0; |
299 | browser->b.nr_entries = browser->hists->nr_entries; | 333 | __hist_browser__set_folding(browser, unfold); |
334 | |||
335 | browser->b.nr_entries = hist_browser__nr_entries(browser); | ||
300 | /* Go to the start, we may be way after valid entries after a collapse */ | 336 | /* Go to the start, we may be way after valid entries after a collapse */ |
301 | ui_browser__reset_index(&browser->b); | 337 | ui_browser__reset_index(&browser->b); |
302 | } | 338 | } |
@@ -310,8 +346,6 @@ static void ui_browser__warn_lost_events(struct ui_browser *browser) | |||
310 | "Or reduce the sampling frequency."); | 346 | "Or reduce the sampling frequency."); |
311 | } | 347 | } |
312 | 348 | ||
313 | static void hist_browser__update_pcnt_entries(struct hist_browser *hb); | ||
314 | |||
315 | static int hist_browser__run(struct hist_browser *browser, const char *ev_name, | 349 | static int hist_browser__run(struct hist_browser *browser, const char *ev_name, |
316 | struct hist_browser_timer *hbt) | 350 | struct hist_browser_timer *hbt) |
317 | { | 351 | { |
@@ -320,9 +354,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, | |||
320 | int delay_secs = hbt ? hbt->refresh : 0; | 354 | int delay_secs = hbt ? hbt->refresh : 0; |
321 | 355 | ||
322 | browser->b.entries = &browser->hists->entries; | 356 | browser->b.entries = &browser->hists->entries; |
323 | browser->b.nr_entries = browser->hists->nr_entries; | 357 | browser->b.nr_entries = hist_browser__nr_entries(browser); |
324 | if (browser->min_pcnt) | ||
325 | browser->b.nr_entries = browser->nr_pcnt_entries; | ||
326 | 358 | ||
327 | hist_browser__refresh_dimensions(browser); | 359 | hist_browser__refresh_dimensions(browser); |
328 | hists__browser_title(browser->hists, title, sizeof(title), ev_name); | 360 | hists__browser_title(browser->hists, title, sizeof(title), ev_name); |
@@ -339,13 +371,10 @@ static int hist_browser__run(struct hist_browser *browser, const char *ev_name, | |||
339 | u64 nr_entries; | 371 | u64 nr_entries; |
340 | hbt->timer(hbt->arg); | 372 | hbt->timer(hbt->arg); |
341 | 373 | ||
342 | if (browser->min_pcnt) { | 374 | if (hist_browser__has_filter(browser)) |
343 | hist_browser__update_pcnt_entries(browser); | 375 | hist_browser__update_nr_entries(browser); |
344 | nr_entries = browser->nr_pcnt_entries; | ||
345 | } else { | ||
346 | nr_entries = browser->hists->nr_entries; | ||
347 | } | ||
348 | 376 | ||
377 | nr_entries = hist_browser__nr_entries(browser); | ||
349 | ui_browser__update_nr_entries(&browser->b, nr_entries); | 378 | ui_browser__update_nr_entries(&browser->b, nr_entries); |
350 | 379 | ||
351 | if (browser->hists->stats.nr_lost_warned != | 380 | if (browser->hists->stats.nr_lost_warned != |
@@ -1343,18 +1372,23 @@ close_file_and_continue: | |||
1343 | return ret; | 1372 | return ret; |
1344 | } | 1373 | } |
1345 | 1374 | ||
1346 | static void hist_browser__update_pcnt_entries(struct hist_browser *hb) | 1375 | static void hist_browser__update_nr_entries(struct hist_browser *hb) |
1347 | { | 1376 | { |
1348 | u64 nr_entries = 0; | 1377 | u64 nr_entries = 0; |
1349 | struct rb_node *nd = rb_first(&hb->hists->entries); | 1378 | struct rb_node *nd = rb_first(&hb->hists->entries); |
1350 | 1379 | ||
1351 | while (nd) { | 1380 | if (hb->min_pcnt == 0) { |
1381 | hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; | ||
1382 | return; | ||
1383 | } | ||
1384 | |||
1385 | while ((nd = hists__filter_entries(nd, hb->hists, | ||
1386 | hb->min_pcnt)) != NULL) { | ||
1352 | nr_entries++; | 1387 | nr_entries++; |
1353 | nd = hists__filter_entries(rb_next(nd), hb->hists, | 1388 | nd = rb_next(nd); |
1354 | hb->min_pcnt); | ||
1355 | } | 1389 | } |
1356 | 1390 | ||
1357 | hb->nr_pcnt_entries = nr_entries; | 1391 | hb->nr_non_filtered_entries = nr_entries; |
1358 | } | 1392 | } |
1359 | 1393 | ||
1360 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | 1394 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
@@ -1411,7 +1445,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1411 | 1445 | ||
1412 | if (min_pcnt) { | 1446 | if (min_pcnt) { |
1413 | browser->min_pcnt = min_pcnt; | 1447 | browser->min_pcnt = min_pcnt; |
1414 | hist_browser__update_pcnt_entries(browser); | 1448 | hist_browser__update_nr_entries(browser); |
1415 | } | 1449 | } |
1416 | 1450 | ||
1417 | fstack = pstack__new(2); | 1451 | fstack = pstack__new(2); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 5a892477aa50..7f0236cea4fe 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -225,14 +225,18 @@ static void he_stat__decay(struct he_stat *he_stat) | |||
225 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | 225 | static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) |
226 | { | 226 | { |
227 | u64 prev_period = he->stat.period; | 227 | u64 prev_period = he->stat.period; |
228 | u64 diff; | ||
228 | 229 | ||
229 | if (prev_period == 0) | 230 | if (prev_period == 0) |
230 | return true; | 231 | return true; |
231 | 232 | ||
232 | he_stat__decay(&he->stat); | 233 | he_stat__decay(&he->stat); |
233 | 234 | ||
235 | diff = prev_period - he->stat.period; | ||
236 | |||
237 | hists->stats.total_period -= diff; | ||
234 | if (!he->filtered) | 238 | if (!he->filtered) |
235 | hists->stats.total_period -= prev_period - he->stat.period; | 239 | hists->stats.total_non_filtered_period -= diff; |
236 | 240 | ||
237 | return he->stat.period == 0; | 241 | return he->stat.period == 0; |
238 | } | 242 | } |
@@ -259,8 +263,11 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | |||
259 | if (sort__need_collapse) | 263 | if (sort__need_collapse) |
260 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); | 264 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); |
261 | 265 | ||
262 | hist_entry__free(n); | ||
263 | --hists->nr_entries; | 266 | --hists->nr_entries; |
267 | if (!n->filtered) | ||
268 | --hists->nr_non_filtered_entries; | ||
269 | |||
270 | hist_entry__free(n); | ||
264 | } | 271 | } |
265 | } | 272 | } |
266 | } | 273 | } |
@@ -317,17 +324,6 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
317 | return he; | 324 | return he; |
318 | } | 325 | } |
319 | 326 | ||
320 | void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) | ||
321 | { | ||
322 | if (!h->filtered) { | ||
323 | hists__calc_col_len(hists, h); | ||
324 | hists->nr_non_filtered_entries++; | ||
325 | hists->stats.total_non_filtered_period += h->stat.period; | ||
326 | } | ||
327 | hists->nr_entries++; | ||
328 | hists->stats.total_period += h->stat.period; | ||
329 | } | ||
330 | |||
331 | static u8 symbol__parent_filter(const struct symbol *parent) | 327 | static u8 symbol__parent_filter(const struct symbol *parent) |
332 | { | 328 | { |
333 | if (symbol_conf.exclude_other && parent == NULL) | 329 | if (symbol_conf.exclude_other && parent == NULL) |
@@ -393,7 +389,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
393 | if (!he) | 389 | if (!he) |
394 | return NULL; | 390 | return NULL; |
395 | 391 | ||
396 | hists->nr_entries++; | ||
397 | rb_link_node(&he->rb_node_in, parent, p); | 392 | rb_link_node(&he->rb_node_in, parent, p); |
398 | rb_insert_color(&he->rb_node_in, hists->entries_in); | 393 | rb_insert_color(&he->rb_node_in, hists->entries_in); |
399 | out: | 394 | out: |
@@ -633,6 +628,35 @@ out: | |||
633 | return ret; | 628 | return ret; |
634 | } | 629 | } |
635 | 630 | ||
631 | static void hists__reset_filter_stats(struct hists *hists) | ||
632 | { | ||
633 | hists->nr_non_filtered_entries = 0; | ||
634 | hists->stats.total_non_filtered_period = 0; | ||
635 | } | ||
636 | |||
637 | void hists__reset_stats(struct hists *hists) | ||
638 | { | ||
639 | hists->nr_entries = 0; | ||
640 | hists->stats.total_period = 0; | ||
641 | |||
642 | hists__reset_filter_stats(hists); | ||
643 | } | ||
644 | |||
645 | static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h) | ||
646 | { | ||
647 | hists->nr_non_filtered_entries++; | ||
648 | hists->stats.total_non_filtered_period += h->stat.period; | ||
649 | } | ||
650 | |||
651 | void hists__inc_stats(struct hists *hists, struct hist_entry *h) | ||
652 | { | ||
653 | if (!h->filtered) | ||
654 | hists__inc_filter_stats(hists, h); | ||
655 | |||
656 | hists->nr_entries++; | ||
657 | hists->stats.total_period += h->stat.period; | ||
658 | } | ||
659 | |||
636 | static void __hists__insert_output_entry(struct rb_root *entries, | 660 | static void __hists__insert_output_entry(struct rb_root *entries, |
637 | struct hist_entry *he, | 661 | struct hist_entry *he, |
638 | u64 min_callchain_hits) | 662 | u64 min_callchain_hits) |
@@ -676,9 +700,7 @@ void hists__output_resort(struct hists *hists) | |||
676 | next = rb_first(root); | 700 | next = rb_first(root); |
677 | hists->entries = RB_ROOT; | 701 | hists->entries = RB_ROOT; |
678 | 702 | ||
679 | hists->nr_non_filtered_entries = 0; | 703 | hists__reset_stats(hists); |
680 | hists->stats.total_period = 0; | ||
681 | hists->stats.total_non_filtered_period = 0; | ||
682 | hists__reset_col_len(hists); | 704 | hists__reset_col_len(hists); |
683 | 705 | ||
684 | while (next) { | 706 | while (next) { |
@@ -686,7 +708,10 @@ void hists__output_resort(struct hists *hists) | |||
686 | next = rb_next(&n->rb_node_in); | 708 | next = rb_next(&n->rb_node_in); |
687 | 709 | ||
688 | __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); | 710 | __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); |
689 | hists__inc_nr_entries(hists, n); | 711 | hists__inc_stats(hists, n); |
712 | |||
713 | if (!n->filtered) | ||
714 | hists__calc_col_len(hists, n); | ||
690 | } | 715 | } |
691 | } | 716 | } |
692 | 717 | ||
@@ -697,13 +722,13 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h | |||
697 | if (h->filtered) | 722 | if (h->filtered) |
698 | return; | 723 | return; |
699 | 724 | ||
700 | ++hists->nr_non_filtered_entries; | 725 | /* force fold unfiltered entry for simplicity */ |
701 | if (h->ms.unfolded) | 726 | h->ms.unfolded = false; |
702 | hists->nr_non_filtered_entries += h->nr_rows; | ||
703 | h->row_offset = 0; | 727 | h->row_offset = 0; |
704 | hists->stats.total_non_filtered_period += h->stat.period; | 728 | |
705 | hists->stats.nr_non_filtered_samples += h->stat.nr_events; | 729 | hists->stats.nr_non_filtered_samples += h->stat.nr_events; |
706 | 730 | ||
731 | hists__inc_filter_stats(hists, h); | ||
707 | hists__calc_col_len(hists, h); | 732 | hists__calc_col_len(hists, h); |
708 | } | 733 | } |
709 | 734 | ||
@@ -724,9 +749,9 @@ void hists__filter_by_dso(struct hists *hists) | |||
724 | { | 749 | { |
725 | struct rb_node *nd; | 750 | struct rb_node *nd; |
726 | 751 | ||
727 | hists->nr_non_filtered_entries = 0; | ||
728 | hists->stats.total_non_filtered_period = 0; | ||
729 | hists->stats.nr_non_filtered_samples = 0; | 752 | hists->stats.nr_non_filtered_samples = 0; |
753 | |||
754 | hists__reset_filter_stats(hists); | ||
730 | hists__reset_col_len(hists); | 755 | hists__reset_col_len(hists); |
731 | 756 | ||
732 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | 757 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
@@ -758,9 +783,9 @@ void hists__filter_by_thread(struct hists *hists) | |||
758 | { | 783 | { |
759 | struct rb_node *nd; | 784 | struct rb_node *nd; |
760 | 785 | ||
761 | hists->nr_non_filtered_entries = 0; | ||
762 | hists->stats.total_non_filtered_period = 0; | ||
763 | hists->stats.nr_non_filtered_samples = 0; | 786 | hists->stats.nr_non_filtered_samples = 0; |
787 | |||
788 | hists__reset_filter_stats(hists); | ||
764 | hists__reset_col_len(hists); | 789 | hists__reset_col_len(hists); |
765 | 790 | ||
766 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | 791 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
@@ -790,9 +815,9 @@ void hists__filter_by_symbol(struct hists *hists) | |||
790 | { | 815 | { |
791 | struct rb_node *nd; | 816 | struct rb_node *nd; |
792 | 817 | ||
793 | hists->nr_non_filtered_entries = 0; | ||
794 | hists->stats.total_non_filtered_period = 0; | ||
795 | hists->stats.nr_non_filtered_samples = 0; | 818 | hists->stats.nr_non_filtered_samples = 0; |
819 | |||
820 | hists__reset_filter_stats(hists); | ||
796 | hists__reset_col_len(hists); | 821 | hists__reset_col_len(hists); |
797 | 822 | ||
798 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | 823 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { |
@@ -853,7 +878,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | |||
853 | he->hists = hists; | 878 | he->hists = hists; |
854 | rb_link_node(&he->rb_node_in, parent, p); | 879 | rb_link_node(&he->rb_node_in, parent, p); |
855 | rb_insert_color(&he->rb_node_in, root); | 880 | rb_insert_color(&he->rb_node_in, root); |
856 | hists__inc_nr_entries(hists, he); | 881 | hists__inc_stats(hists, he); |
857 | he->dummy = true; | 882 | he->dummy = true; |
858 | } | 883 | } |
859 | out: | 884 | out: |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 5a0343eb22e2..38c3e874c164 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -116,7 +116,8 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); | |||
116 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); | 116 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); |
117 | 117 | ||
118 | u64 hists__total_period(struct hists *hists); | 118 | u64 hists__total_period(struct hists *hists); |
119 | void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); | 119 | void hists__reset_stats(struct hists *hists); |
120 | void hists__inc_stats(struct hists *hists, struct hist_entry *h); | ||
120 | void hists__inc_nr_events(struct hists *hists, u32 type); | 121 | void hists__inc_nr_events(struct hists *hists, u32 type); |
121 | void events_stats__inc(struct events_stats *stats, u32 type); | 122 | void events_stats__inc(struct events_stats *stats, u32 type); |
122 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); | 123 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); |
@@ -128,6 +129,12 @@ void hists__filter_by_dso(struct hists *hists); | |||
128 | void hists__filter_by_thread(struct hists *hists); | 129 | void hists__filter_by_thread(struct hists *hists); |
129 | void hists__filter_by_symbol(struct hists *hists); | 130 | void hists__filter_by_symbol(struct hists *hists); |
130 | 131 | ||
132 | static inline bool hists__has_filter(struct hists *hists) | ||
133 | { | ||
134 | return hists->thread_filter || hists->dso_filter || | ||
135 | hists->symbol_filter_str; | ||
136 | } | ||
137 | |||
131 | u16 hists__col_len(struct hists *hists, enum hist_column col); | 138 | u16 hists__col_len(struct hists *hists, enum hist_column col); |
132 | void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len); | 139 | void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len); |
133 | bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len); | 140 | bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len); |