diff options
Diffstat (limited to 'tools/perf/util/hist.c')
| -rw-r--r-- | tools/perf/util/hist.c | 96 |
1 files changed, 42 insertions, 54 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6b32721f829a..b11a6cfdb414 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -70,9 +70,17 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
| 70 | int symlen; | 70 | int symlen; |
| 71 | u16 len; | 71 | u16 len; |
| 72 | 72 | ||
| 73 | if (h->ms.sym) | 73 | /* |
| 74 | hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); | 74 | * +4 accounts for '[x] ' priv level info |
| 75 | else { | 75 | * +2 accounts for 0x prefix on raw addresses |
| 76 | * +3 accounts for ' y ' symtab origin info | ||
| 77 | */ | ||
| 78 | if (h->ms.sym) { | ||
| 79 | symlen = h->ms.sym->namelen + 4; | ||
| 80 | if (verbose) | ||
| 81 | symlen += BITS_PER_LONG / 4 + 2 + 3; | ||
| 82 | hists__new_col_len(hists, HISTC_SYMBOL, symlen); | ||
| 83 | } else { | ||
| 76 | symlen = unresolved_col_width + 4 + 2; | 84 | symlen = unresolved_col_width + 4 + 2; |
| 77 | hists__new_col_len(hists, HISTC_SYMBOL, symlen); | 85 | hists__new_col_len(hists, HISTC_SYMBOL, symlen); |
| 78 | hists__set_unres_dso_col_len(hists, HISTC_DSO); | 86 | hists__set_unres_dso_col_len(hists, HISTC_DSO); |
| @@ -91,12 +99,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
| 91 | hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); | 99 | hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen); |
| 92 | 100 | ||
| 93 | if (h->branch_info) { | 101 | if (h->branch_info) { |
| 94 | /* | ||
| 95 | * +4 accounts for '[x] ' priv level info | ||
| 96 | * +2 account of 0x prefix on raw addresses | ||
| 97 | */ | ||
| 98 | if (h->branch_info->from.sym) { | 102 | if (h->branch_info->from.sym) { |
| 99 | symlen = (int)h->branch_info->from.sym->namelen + 4; | 103 | symlen = (int)h->branch_info->from.sym->namelen + 4; |
| 104 | if (verbose) | ||
| 105 | symlen += BITS_PER_LONG / 4 + 2 + 3; | ||
| 100 | hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); | 106 | hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); |
| 101 | 107 | ||
| 102 | symlen = dso__name_len(h->branch_info->from.map->dso); | 108 | symlen = dso__name_len(h->branch_info->from.map->dso); |
| @@ -109,6 +115,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
| 109 | 115 | ||
| 110 | if (h->branch_info->to.sym) { | 116 | if (h->branch_info->to.sym) { |
| 111 | symlen = (int)h->branch_info->to.sym->namelen + 4; | 117 | symlen = (int)h->branch_info->to.sym->namelen + 4; |
| 118 | if (verbose) | ||
| 119 | symlen += BITS_PER_LONG / 4 + 2 + 3; | ||
| 112 | hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); | 120 | hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); |
| 113 | 121 | ||
| 114 | symlen = dso__name_len(h->branch_info->to.map->dso); | 122 | symlen = dso__name_len(h->branch_info->to.map->dso); |
| @@ -121,10 +129,6 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) | |||
| 121 | } | 129 | } |
| 122 | 130 | ||
| 123 | if (h->mem_info) { | 131 | if (h->mem_info) { |
| 124 | /* | ||
| 125 | * +4 accounts for '[x] ' priv level info | ||
| 126 | * +2 account of 0x prefix on raw addresses | ||
| 127 | */ | ||
| 128 | if (h->mem_info->daddr.sym) { | 132 | if (h->mem_info->daddr.sym) { |
| 129 | symlen = (int)h->mem_info->daddr.sym->namelen + 4 | 133 | symlen = (int)h->mem_info->daddr.sym->namelen + 4 |
| 130 | + unresolved_col_width + 2; | 134 | + unresolved_col_width + 2; |
| @@ -236,8 +240,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | |||
| 236 | return he->stat.period == 0; | 240 | return he->stat.period == 0; |
| 237 | } | 241 | } |
| 238 | 242 | ||
| 239 | static void __hists__decay_entries(struct hists *hists, bool zap_user, | 243 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) |
| 240 | bool zap_kernel, bool threaded) | ||
| 241 | { | 244 | { |
| 242 | struct rb_node *next = rb_first(&hists->entries); | 245 | struct rb_node *next = rb_first(&hists->entries); |
| 243 | struct hist_entry *n; | 246 | struct hist_entry *n; |
| @@ -256,7 +259,7 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user, | |||
| 256 | !n->used) { | 259 | !n->used) { |
| 257 | rb_erase(&n->rb_node, &hists->entries); | 260 | rb_erase(&n->rb_node, &hists->entries); |
| 258 | 261 | ||
| 259 | if (sort__need_collapse || threaded) | 262 | if (sort__need_collapse) |
| 260 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); | 263 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); |
| 261 | 264 | ||
| 262 | hist_entry__free(n); | 265 | hist_entry__free(n); |
| @@ -265,17 +268,6 @@ static void __hists__decay_entries(struct hists *hists, bool zap_user, | |||
| 265 | } | 268 | } |
| 266 | } | 269 | } |
| 267 | 270 | ||
| 268 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | ||
| 269 | { | ||
| 270 | return __hists__decay_entries(hists, zap_user, zap_kernel, false); | ||
| 271 | } | ||
| 272 | |||
| 273 | void hists__decay_entries_threaded(struct hists *hists, | ||
| 274 | bool zap_user, bool zap_kernel) | ||
| 275 | { | ||
| 276 | return __hists__decay_entries(hists, zap_user, zap_kernel, true); | ||
| 277 | } | ||
| 278 | |||
| 279 | /* | 271 | /* |
| 280 | * histogram, sorted on item, collects periods | 272 | * histogram, sorted on item, collects periods |
| 281 | */ | 273 | */ |
| @@ -292,6 +284,20 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) | |||
| 292 | he->ms.map->referenced = true; | 284 | he->ms.map->referenced = true; |
| 293 | 285 | ||
| 294 | if (he->branch_info) { | 286 | if (he->branch_info) { |
| 287 | /* | ||
| 288 | * This branch info is (a part of) allocated from | ||
| 289 | * machine__resolve_bstack() and will be freed after | ||
| 290 | * adding new entries. So we need to save a copy. | ||
| 291 | */ | ||
| 292 | he->branch_info = malloc(sizeof(*he->branch_info)); | ||
| 293 | if (he->branch_info == NULL) { | ||
| 294 | free(he); | ||
| 295 | return NULL; | ||
| 296 | } | ||
| 297 | |||
| 298 | memcpy(he->branch_info, template->branch_info, | ||
| 299 | sizeof(*he->branch_info)); | ||
| 300 | |||
| 295 | if (he->branch_info->from.map) | 301 | if (he->branch_info->from.map) |
| 296 | he->branch_info->from.map->referenced = true; | 302 | he->branch_info->from.map->referenced = true; |
| 297 | if (he->branch_info->to.map) | 303 | if (he->branch_info->to.map) |
| @@ -341,8 +347,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
| 341 | struct hist_entry *he; | 347 | struct hist_entry *he; |
| 342 | int cmp; | 348 | int cmp; |
| 343 | 349 | ||
| 344 | pthread_mutex_lock(&hists->lock); | ||
| 345 | |||
| 346 | p = &hists->entries_in->rb_node; | 350 | p = &hists->entries_in->rb_node; |
| 347 | 351 | ||
| 348 | while (*p != NULL) { | 352 | while (*p != NULL) { |
| @@ -360,6 +364,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
| 360 | if (!cmp) { | 364 | if (!cmp) { |
| 361 | he_stat__add_period(&he->stat, period, weight); | 365 | he_stat__add_period(&he->stat, period, weight); |
| 362 | 366 | ||
| 367 | /* | ||
| 368 | * This mem info was allocated from machine__resolve_mem | ||
| 369 | * and will not be used anymore. | ||
| 370 | */ | ||
| 371 | free(entry->mem_info); | ||
| 372 | |||
| 363 | /* If the map of an existing hist_entry has | 373 | /* If the map of an existing hist_entry has |
| 364 | * become out-of-date due to an exec() or | 374 | * become out-of-date due to an exec() or |
| 365 | * similar, update it. Otherwise we will | 375 | * similar, update it. Otherwise we will |
| @@ -382,14 +392,12 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
| 382 | 392 | ||
| 383 | he = hist_entry__new(entry); | 393 | he = hist_entry__new(entry); |
| 384 | if (!he) | 394 | if (!he) |
| 385 | goto out_unlock; | 395 | return NULL; |
| 386 | 396 | ||
| 387 | rb_link_node(&he->rb_node_in, parent, p); | 397 | rb_link_node(&he->rb_node_in, parent, p); |
| 388 | rb_insert_color(&he->rb_node_in, hists->entries_in); | 398 | rb_insert_color(&he->rb_node_in, hists->entries_in); |
| 389 | out: | 399 | out: |
| 390 | hist_entry__add_cpumode_period(he, al->cpumode, period); | 400 | hist_entry__add_cpumode_period(he, al->cpumode, period); |
| 391 | out_unlock: | ||
| 392 | pthread_mutex_unlock(&hists->lock); | ||
| 393 | return he; | 401 | return he; |
| 394 | } | 402 | } |
| 395 | 403 | ||
| @@ -589,13 +597,13 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he) | |||
| 589 | hists__filter_entry_by_symbol(hists, he); | 597 | hists__filter_entry_by_symbol(hists, he); |
| 590 | } | 598 | } |
| 591 | 599 | ||
| 592 | static void __hists__collapse_resort(struct hists *hists, bool threaded) | 600 | void hists__collapse_resort(struct hists *hists) |
| 593 | { | 601 | { |
| 594 | struct rb_root *root; | 602 | struct rb_root *root; |
| 595 | struct rb_node *next; | 603 | struct rb_node *next; |
| 596 | struct hist_entry *n; | 604 | struct hist_entry *n; |
| 597 | 605 | ||
| 598 | if (!sort__need_collapse && !threaded) | 606 | if (!sort__need_collapse) |
| 599 | return; | 607 | return; |
| 600 | 608 | ||
| 601 | root = hists__get_rotate_entries_in(hists); | 609 | root = hists__get_rotate_entries_in(hists); |
| @@ -617,16 +625,6 @@ static void __hists__collapse_resort(struct hists *hists, bool threaded) | |||
| 617 | } | 625 | } |
| 618 | } | 626 | } |
| 619 | 627 | ||
| 620 | void hists__collapse_resort(struct hists *hists) | ||
| 621 | { | ||
| 622 | return __hists__collapse_resort(hists, false); | ||
| 623 | } | ||
| 624 | |||
| 625 | void hists__collapse_resort_threaded(struct hists *hists) | ||
| 626 | { | ||
| 627 | return __hists__collapse_resort(hists, true); | ||
| 628 | } | ||
| 629 | |||
| 630 | /* | 628 | /* |
| 631 | * reverse the map, sort on period. | 629 | * reverse the map, sort on period. |
| 632 | */ | 630 | */ |
| @@ -713,7 +711,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, | |||
| 713 | rb_insert_color(&he->rb_node, entries); | 711 | rb_insert_color(&he->rb_node, entries); |
| 714 | } | 712 | } |
| 715 | 713 | ||
| 716 | static void __hists__output_resort(struct hists *hists, bool threaded) | 714 | void hists__output_resort(struct hists *hists) |
| 717 | { | 715 | { |
| 718 | struct rb_root *root; | 716 | struct rb_root *root; |
| 719 | struct rb_node *next; | 717 | struct rb_node *next; |
| @@ -722,7 +720,7 @@ static void __hists__output_resort(struct hists *hists, bool threaded) | |||
| 722 | 720 | ||
| 723 | min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); | 721 | min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); |
| 724 | 722 | ||
| 725 | if (sort__need_collapse || threaded) | 723 | if (sort__need_collapse) |
| 726 | root = &hists->entries_collapsed; | 724 | root = &hists->entries_collapsed; |
| 727 | else | 725 | else |
| 728 | root = hists->entries_in; | 726 | root = hists->entries_in; |
| @@ -743,16 +741,6 @@ static void __hists__output_resort(struct hists *hists, bool threaded) | |||
| 743 | } | 741 | } |
| 744 | } | 742 | } |
| 745 | 743 | ||
| 746 | void hists__output_resort(struct hists *hists) | ||
| 747 | { | ||
| 748 | return __hists__output_resort(hists, false); | ||
| 749 | } | ||
| 750 | |||
| 751 | void hists__output_resort_threaded(struct hists *hists) | ||
| 752 | { | ||
| 753 | return __hists__output_resort(hists, true); | ||
| 754 | } | ||
| 755 | |||
| 756 | static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, | 744 | static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, |
| 757 | enum hist_filter filter) | 745 | enum hist_filter filter) |
| 758 | { | 746 | { |
