diff options
Diffstat (limited to 'tools/perf/util/hist.c')
| -rw-r--r-- | tools/perf/util/hist.c | 121 |
1 files changed, 74 insertions, 47 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 5dc4f8429eda..f75c5f62401c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -9,21 +9,21 @@ struct callchain_param callchain_param = { | |||
| 9 | .min_percent = 0.5 | 9 | .min_percent = 0.5 |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | static void hist_entry__add_cpumode_count(struct hist_entry *self, | 12 | static void hist_entry__add_cpumode_period(struct hist_entry *self, |
| 13 | unsigned int cpumode, u64 count) | 13 | unsigned int cpumode, u64 period) |
| 14 | { | 14 | { |
| 15 | switch (cpumode) { | 15 | switch (cpumode) { |
| 16 | case PERF_RECORD_MISC_KERNEL: | 16 | case PERF_RECORD_MISC_KERNEL: |
| 17 | self->count_sys += count; | 17 | self->period_sys += period; |
| 18 | break; | 18 | break; |
| 19 | case PERF_RECORD_MISC_USER: | 19 | case PERF_RECORD_MISC_USER: |
| 20 | self->count_us += count; | 20 | self->period_us += period; |
| 21 | break; | 21 | break; |
| 22 | case PERF_RECORD_MISC_GUEST_KERNEL: | 22 | case PERF_RECORD_MISC_GUEST_KERNEL: |
| 23 | self->count_guest_sys += count; | 23 | self->period_guest_sys += period; |
| 24 | break; | 24 | break; |
| 25 | case PERF_RECORD_MISC_GUEST_USER: | 25 | case PERF_RECORD_MISC_GUEST_USER: |
| 26 | self->count_guest_us += count; | 26 | self->period_guest_us += period; |
| 27 | break; | 27 | break; |
| 28 | default: | 28 | default: |
| 29 | break; | 29 | break; |
| @@ -31,7 +31,7 @@ static void hist_entry__add_cpumode_count(struct hist_entry *self, | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | /* | 33 | /* |
| 34 | * histogram, sorted on item, collects counts | 34 | * histogram, sorted on item, collects periods |
| 35 | */ | 35 | */ |
| 36 | 36 | ||
| 37 | static struct hist_entry *hist_entry__new(struct hist_entry *template) | 37 | static struct hist_entry *hist_entry__new(struct hist_entry *template) |
| @@ -41,6 +41,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
| 41 | 41 | ||
| 42 | if (self != NULL) { | 42 | if (self != NULL) { |
| 43 | *self = *template; | 43 | *self = *template; |
| 44 | self->nr_events = 1; | ||
| 44 | if (symbol_conf.use_callchain) | 45 | if (symbol_conf.use_callchain) |
| 45 | callchain_init(self->callchain); | 46 | callchain_init(self->callchain); |
| 46 | } | 47 | } |
| @@ -57,7 +58,7 @@ static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry) | |||
| 57 | 58 | ||
| 58 | struct hist_entry *__hists__add_entry(struct hists *self, | 59 | struct hist_entry *__hists__add_entry(struct hists *self, |
| 59 | struct addr_location *al, | 60 | struct addr_location *al, |
| 60 | struct symbol *sym_parent, u64 count) | 61 | struct symbol *sym_parent, u64 period) |
| 61 | { | 62 | { |
| 62 | struct rb_node **p = &self->entries.rb_node; | 63 | struct rb_node **p = &self->entries.rb_node; |
| 63 | struct rb_node *parent = NULL; | 64 | struct rb_node *parent = NULL; |
| @@ -70,7 +71,7 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
| 70 | }, | 71 | }, |
| 71 | .ip = al->addr, | 72 | .ip = al->addr, |
| 72 | .level = al->level, | 73 | .level = al->level, |
| 73 | .count = count, | 74 | .period = period, |
| 74 | .parent = sym_parent, | 75 | .parent = sym_parent, |
| 75 | }; | 76 | }; |
| 76 | int cmp; | 77 | int cmp; |
| @@ -82,7 +83,8 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
| 82 | cmp = hist_entry__cmp(&entry, he); | 83 | cmp = hist_entry__cmp(&entry, he); |
| 83 | 84 | ||
| 84 | if (!cmp) { | 85 | if (!cmp) { |
| 85 | he->count += count; | 86 | he->period += period; |
| 87 | ++he->nr_events; | ||
| 86 | goto out; | 88 | goto out; |
| 87 | } | 89 | } |
| 88 | 90 | ||
| @@ -99,7 +101,7 @@ struct hist_entry *__hists__add_entry(struct hists *self, | |||
| 99 | rb_insert_color(&he->rb_node, &self->entries); | 101 | rb_insert_color(&he->rb_node, &self->entries); |
| 100 | hists__inc_nr_entries(self, he); | 102 | hists__inc_nr_entries(self, he); |
| 101 | out: | 103 | out: |
| 102 | hist_entry__add_cpumode_count(he, al->cpumode, count); | 104 | hist_entry__add_cpumode_period(he, al->cpumode, period); |
| 103 | return he; | 105 | return he; |
| 104 | } | 106 | } |
| 105 | 107 | ||
| @@ -160,7 +162,7 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he) | |||
| 160 | cmp = hist_entry__collapse(iter, he); | 162 | cmp = hist_entry__collapse(iter, he); |
| 161 | 163 | ||
| 162 | if (!cmp) { | 164 | if (!cmp) { |
| 163 | iter->count += he->count; | 165 | iter->period += he->period; |
| 164 | hist_entry__free(he); | 166 | hist_entry__free(he); |
| 165 | return false; | 167 | return false; |
| 166 | } | 168 | } |
| @@ -203,7 +205,7 @@ void hists__collapse_resort(struct hists *self) | |||
| 203 | } | 205 | } |
| 204 | 206 | ||
| 205 | /* | 207 | /* |
| 206 | * reverse the map, sort on count. | 208 | * reverse the map, sort on period. |
| 207 | */ | 209 | */ |
| 208 | 210 | ||
| 209 | static void __hists__insert_output_entry(struct rb_root *entries, | 211 | static void __hists__insert_output_entry(struct rb_root *entries, |
| @@ -222,7 +224,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, | |||
| 222 | parent = *p; | 224 | parent = *p; |
| 223 | iter = rb_entry(parent, struct hist_entry, rb_node); | 225 | iter = rb_entry(parent, struct hist_entry, rb_node); |
| 224 | 226 | ||
| 225 | if (he->count > iter->count) | 227 | if (he->period > iter->period) |
| 226 | p = &(*p)->rb_left; | 228 | p = &(*p)->rb_left; |
| 227 | else | 229 | else |
| 228 | p = &(*p)->rb_right; | 230 | p = &(*p)->rb_right; |
| @@ -239,7 +241,7 @@ void hists__output_resort(struct hists *self) | |||
| 239 | struct hist_entry *n; | 241 | struct hist_entry *n; |
| 240 | u64 min_callchain_hits; | 242 | u64 min_callchain_hits; |
| 241 | 243 | ||
| 242 | min_callchain_hits = self->stats.total * (callchain_param.min_percent / 100); | 244 | min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100); |
| 243 | 245 | ||
| 244 | tmp = RB_ROOT; | 246 | tmp = RB_ROOT; |
| 245 | next = rb_first(&self->entries); | 247 | next = rb_first(&self->entries); |
| @@ -288,7 +290,7 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, | |||
| 288 | } | 290 | } |
| 289 | 291 | ||
| 290 | static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, | 292 | static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, |
| 291 | int depth, int depth_mask, int count, | 293 | int depth, int depth_mask, int period, |
| 292 | u64 total_samples, int hits, | 294 | u64 total_samples, int hits, |
| 293 | int left_margin) | 295 | int left_margin) |
| 294 | { | 296 | { |
| @@ -301,7 +303,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, | |||
| 301 | ret += fprintf(fp, "|"); | 303 | ret += fprintf(fp, "|"); |
| 302 | else | 304 | else |
| 303 | ret += fprintf(fp, " "); | 305 | ret += fprintf(fp, " "); |
| 304 | if (!count && i == depth - 1) { | 306 | if (!period && i == depth - 1) { |
| 305 | double percent; | 307 | double percent; |
| 306 | 308 | ||
| 307 | percent = hits * 100.0 / total_samples; | 309 | percent = hits * 100.0 / total_samples; |
| @@ -516,7 +518,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, | |||
| 516 | long displacement, bool color, u64 session_total) | 518 | long displacement, bool color, u64 session_total) |
| 517 | { | 519 | { |
| 518 | struct sort_entry *se; | 520 | struct sort_entry *se; |
| 519 | u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us; | 521 | u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; |
| 520 | const char *sep = symbol_conf.field_sep; | 522 | const char *sep = symbol_conf.field_sep; |
| 521 | int ret; | 523 | int ret; |
| 522 | 524 | ||
| @@ -524,57 +526,57 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, | |||
| 524 | return 0; | 526 | return 0; |
| 525 | 527 | ||
| 526 | if (pair_hists) { | 528 | if (pair_hists) { |
| 527 | count = self->pair ? self->pair->count : 0; | 529 | period = self->pair ? self->pair->period : 0; |
| 528 | total = pair_hists->stats.total; | 530 | total = pair_hists->stats.total_period; |
| 529 | count_sys = self->pair ? self->pair->count_sys : 0; | 531 | period_sys = self->pair ? self->pair->period_sys : 0; |
| 530 | count_us = self->pair ? self->pair->count_us : 0; | 532 | period_us = self->pair ? self->pair->period_us : 0; |
| 531 | count_guest_sys = self->pair ? self->pair->count_guest_sys : 0; | 533 | period_guest_sys = self->pair ? self->pair->period_guest_sys : 0; |
| 532 | count_guest_us = self->pair ? self->pair->count_guest_us : 0; | 534 | period_guest_us = self->pair ? self->pair->period_guest_us : 0; |
| 533 | } else { | 535 | } else { |
| 534 | count = self->count; | 536 | period = self->period; |
| 535 | total = session_total; | 537 | total = session_total; |
| 536 | count_sys = self->count_sys; | 538 | period_sys = self->period_sys; |
| 537 | count_us = self->count_us; | 539 | period_us = self->period_us; |
| 538 | count_guest_sys = self->count_guest_sys; | 540 | period_guest_sys = self->period_guest_sys; |
| 539 | count_guest_us = self->count_guest_us; | 541 | period_guest_us = self->period_guest_us; |
| 540 | } | 542 | } |
| 541 | 543 | ||
| 542 | if (total) { | 544 | if (total) { |
| 543 | if (color) | 545 | if (color) |
| 544 | ret = percent_color_snprintf(s, size, | 546 | ret = percent_color_snprintf(s, size, |
| 545 | sep ? "%.2f" : " %6.2f%%", | 547 | sep ? "%.2f" : " %6.2f%%", |
| 546 | (count * 100.0) / total); | 548 | (period * 100.0) / total); |
| 547 | else | 549 | else |
| 548 | ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", | 550 | ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", |
| 549 | (count * 100.0) / total); | 551 | (period * 100.0) / total); |
| 550 | if (symbol_conf.show_cpu_utilization) { | 552 | if (symbol_conf.show_cpu_utilization) { |
| 551 | ret += percent_color_snprintf(s + ret, size - ret, | 553 | ret += percent_color_snprintf(s + ret, size - ret, |
| 552 | sep ? "%.2f" : " %6.2f%%", | 554 | sep ? "%.2f" : " %6.2f%%", |
| 553 | (count_sys * 100.0) / total); | 555 | (period_sys * 100.0) / total); |
| 554 | ret += percent_color_snprintf(s + ret, size - ret, | 556 | ret += percent_color_snprintf(s + ret, size - ret, |
| 555 | sep ? "%.2f" : " %6.2f%%", | 557 | sep ? "%.2f" : " %6.2f%%", |
| 556 | (count_us * 100.0) / total); | 558 | (period_us * 100.0) / total); |
| 557 | if (perf_guest) { | 559 | if (perf_guest) { |
| 558 | ret += percent_color_snprintf(s + ret, | 560 | ret += percent_color_snprintf(s + ret, |
| 559 | size - ret, | 561 | size - ret, |
| 560 | sep ? "%.2f" : " %6.2f%%", | 562 | sep ? "%.2f" : " %6.2f%%", |
| 561 | (count_guest_sys * 100.0) / | 563 | (period_guest_sys * 100.0) / |
| 562 | total); | 564 | total); |
| 563 | ret += percent_color_snprintf(s + ret, | 565 | ret += percent_color_snprintf(s + ret, |
| 564 | size - ret, | 566 | size - ret, |
| 565 | sep ? "%.2f" : " %6.2f%%", | 567 | sep ? "%.2f" : " %6.2f%%", |
| 566 | (count_guest_us * 100.0) / | 568 | (period_guest_us * 100.0) / |
| 567 | total); | 569 | total); |
| 568 | } | 570 | } |
| 569 | } | 571 | } |
| 570 | } else | 572 | } else |
| 571 | ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count); | 573 | ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period); |
| 572 | 574 | ||
| 573 | if (symbol_conf.show_nr_samples) { | 575 | if (symbol_conf.show_nr_samples) { |
| 574 | if (sep) | 576 | if (sep) |
| 575 | ret += snprintf(s + ret, size - ret, "%c%lld", *sep, count); | 577 | ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period); |
| 576 | else | 578 | else |
| 577 | ret += snprintf(s + ret, size - ret, "%11lld", count); | 579 | ret += snprintf(s + ret, size - ret, "%11lld", period); |
| 578 | } | 580 | } |
| 579 | 581 | ||
| 580 | if (pair_hists) { | 582 | if (pair_hists) { |
| @@ -582,9 +584,9 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size, | |||
| 582 | double old_percent = 0, new_percent = 0, diff; | 584 | double old_percent = 0, new_percent = 0, diff; |
| 583 | 585 | ||
| 584 | if (total > 0) | 586 | if (total > 0) |
| 585 | old_percent = (count * 100.0) / total; | 587 | old_percent = (period * 100.0) / total; |
| 586 | if (session_total > 0) | 588 | if (session_total > 0) |
| 587 | new_percent = (self->count * 100.0) / session_total; | 589 | new_percent = (self->period * 100.0) / session_total; |
| 588 | 590 | ||
| 589 | diff = new_percent - old_percent; | 591 | diff = new_percent - old_percent; |
| 590 | 592 | ||
| @@ -769,10 +771,10 @@ print_entries: | |||
| 769 | ++position; | 771 | ++position; |
| 770 | } | 772 | } |
| 771 | ret += hist_entry__fprintf(h, pair, show_displacement, | 773 | ret += hist_entry__fprintf(h, pair, show_displacement, |
| 772 | displacement, fp, self->stats.total); | 774 | displacement, fp, self->stats.total_period); |
| 773 | 775 | ||
| 774 | if (symbol_conf.use_callchain) | 776 | if (symbol_conf.use_callchain) |
| 775 | ret += hist_entry__fprintf_callchain(h, fp, self->stats.total); | 777 | ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period); |
| 776 | 778 | ||
| 777 | if (h->ms.map == NULL && verbose > 1) { | 779 | if (h->ms.map == NULL && verbose > 1) { |
| 778 | __map_groups__fprintf_maps(&h->thread->mg, | 780 | __map_groups__fprintf_maps(&h->thread->mg, |
| @@ -795,7 +797,8 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso) | |||
| 795 | { | 797 | { |
| 796 | struct rb_node *nd; | 798 | struct rb_node *nd; |
| 797 | 799 | ||
| 798 | self->nr_entries = self->stats.total = 0; | 800 | self->nr_entries = self->stats.total_period = 0; |
| 801 | self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; | ||
| 799 | self->max_sym_namelen = 0; | 802 | self->max_sym_namelen = 0; |
| 800 | 803 | ||
| 801 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | 804 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { |
| @@ -812,7 +815,8 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso) | |||
| 812 | h->filtered &= ~(1 << HIST_FILTER__DSO); | 815 | h->filtered &= ~(1 << HIST_FILTER__DSO); |
| 813 | if (!h->filtered) { | 816 | if (!h->filtered) { |
| 814 | ++self->nr_entries; | 817 | ++self->nr_entries; |
| 815 | self->stats.total += h->count; | 818 | self->stats.total_period += h->period; |
| 819 | self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; | ||
| 816 | if (h->ms.sym && | 820 | if (h->ms.sym && |
| 817 | self->max_sym_namelen < h->ms.sym->namelen) | 821 | self->max_sym_namelen < h->ms.sym->namelen) |
| 818 | self->max_sym_namelen = h->ms.sym->namelen; | 822 | self->max_sym_namelen = h->ms.sym->namelen; |
| @@ -824,7 +828,8 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread) | |||
| 824 | { | 828 | { |
| 825 | struct rb_node *nd; | 829 | struct rb_node *nd; |
| 826 | 830 | ||
| 827 | self->nr_entries = self->stats.total = 0; | 831 | self->nr_entries = self->stats.total_period = 0; |
| 832 | self->stats.nr_events[PERF_RECORD_SAMPLE] = 0; | ||
| 828 | self->max_sym_namelen = 0; | 833 | self->max_sym_namelen = 0; |
| 829 | 834 | ||
| 830 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | 835 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { |
| @@ -837,7 +842,8 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread) | |||
| 837 | h->filtered &= ~(1 << HIST_FILTER__THREAD); | 842 | h->filtered &= ~(1 << HIST_FILTER__THREAD); |
| 838 | if (!h->filtered) { | 843 | if (!h->filtered) { |
| 839 | ++self->nr_entries; | 844 | ++self->nr_entries; |
| 840 | self->stats.total += h->count; | 845 | self->stats.total_period += h->period; |
| 846 | self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; | ||
| 841 | if (h->ms.sym && | 847 | if (h->ms.sym && |
| 842 | self->max_sym_namelen < h->ms.sym->namelen) | 848 | self->max_sym_namelen < h->ms.sym->namelen) |
| 843 | self->max_sym_namelen = h->ms.sym->namelen; | 849 | self->max_sym_namelen = h->ms.sym->namelen; |
| @@ -881,7 +887,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip) | |||
| 881 | h->sum++; | 887 | h->sum++; |
| 882 | h->ip[offset]++; | 888 | h->ip[offset]++; |
| 883 | 889 | ||
| 884 | pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start, | 890 | pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start, |
| 885 | self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]); | 891 | self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]); |
| 886 | return 0; | 892 | return 0; |
| 887 | } | 893 | } |
| @@ -1028,3 +1034,24 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) | |||
| 1028 | pclose(file); | 1034 | pclose(file); |
| 1029 | return 0; | 1035 | return 0; |
| 1030 | } | 1036 | } |
| 1037 | |||
| 1038 | void hists__inc_nr_events(struct hists *self, u32 type) | ||
| 1039 | { | ||
| 1040 | ++self->stats.nr_events[0]; | ||
| 1041 | ++self->stats.nr_events[type]; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) | ||
| 1045 | { | ||
| 1046 | int i; | ||
| 1047 | size_t ret = 0; | ||
| 1048 | |||
| 1049 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { | ||
| 1050 | if (!event__name[i]) | ||
| 1051 | continue; | ||
| 1052 | ret += fprintf(fp, "%10s events: %10d\n", | ||
| 1053 | event__name[i], self->stats.nr_events[i]); | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | return ret; | ||
| 1057 | } | ||
