diff options
| -rw-r--r-- | tools/perf/util/newt.c | 82 | ||||
| -rw-r--r-- | tools/perf/util/sort.h | 9 |
2 files changed, 81 insertions, 10 deletions
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index bbf725d4b38d..6d6e022d7708 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
| @@ -490,6 +490,11 @@ static int hist_browser__populate(struct hist_browser *self, struct rb_root *his | |||
| 490 | return 0; | 490 | return 0; |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | enum hist_filter { | ||
| 494 | HIST_FILTER__DSO, | ||
| 495 | HIST_FILTER__THREAD, | ||
| 496 | }; | ||
| 497 | |||
| 493 | static u64 hists__filter_by_dso(struct rb_root *hists, struct dso *dso, | 498 | static u64 hists__filter_by_dso(struct rb_root *hists, struct dso *dso, |
| 494 | u64 *session_total) | 499 | u64 *session_total) |
| 495 | { | 500 | { |
| @@ -502,10 +507,10 @@ static u64 hists__filter_by_dso(struct rb_root *hists, struct dso *dso, | |||
| 502 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 507 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 503 | 508 | ||
| 504 | if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { | 509 | if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) { |
| 505 | h->filtered = true; | 510 | h->filtered |= (1 << HIST_FILTER__DSO); |
| 506 | continue; | 511 | continue; |
| 507 | } | 512 | } |
| 508 | h->filtered = false; | 513 | h->filtered &= ~(1 << HIST_FILTER__DSO); |
| 509 | ++nr_hists; | 514 | ++nr_hists; |
| 510 | *session_total += h->count; | 515 | *session_total += h->count; |
| 511 | } | 516 | } |
| @@ -513,12 +518,54 @@ static u64 hists__filter_by_dso(struct rb_root *hists, struct dso *dso, | |||
| 513 | return nr_hists; | 518 | return nr_hists; |
| 514 | } | 519 | } |
| 515 | 520 | ||
| 521 | static u64 hists__filter_by_thread(struct rb_root *hists, const struct thread *thread, | ||
| 522 | u64 *session_total) | ||
| 523 | { | ||
| 524 | struct rb_node *nd; | ||
| 525 | u64 nr_hists = 0; | ||
| 526 | |||
| 527 | *session_total = 0; | ||
| 528 | |||
| 529 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { | ||
| 530 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
| 531 | |||
| 532 | if (thread != NULL && h->thread != thread) { | ||
| 533 | h->filtered |= (1 << HIST_FILTER__THREAD); | ||
| 534 | continue; | ||
| 535 | } | ||
| 536 | h->filtered &= ~(1 << HIST_FILTER__THREAD); | ||
| 537 | ++nr_hists; | ||
| 538 | *session_total += h->count; | ||
| 539 | } | ||
| 540 | |||
| 541 | return nr_hists; | ||
| 542 | } | ||
| 543 | |||
| 544 | static struct thread *hist_browser__selected_thread(struct hist_browser *self) | ||
| 545 | { | ||
| 546 | int *indexes; | ||
| 547 | |||
| 548 | if (!symbol_conf.use_callchain) | ||
| 549 | goto out; | ||
| 550 | |||
| 551 | indexes = newtCheckboxTreeFindItem(self->tree, (void *)self->selection); | ||
| 552 | if (indexes) { | ||
| 553 | bool is_hist_entry = indexes[1] == NEWT_ARG_LAST; | ||
| 554 | free(indexes); | ||
| 555 | if (is_hist_entry) | ||
| 556 | goto out; | ||
| 557 | } | ||
| 558 | return NULL; | ||
| 559 | out: | ||
| 560 | return *(struct thread **)(self->selection + 1); | ||
| 561 | } | ||
| 562 | |||
| 516 | int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | 563 | int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, |
| 517 | u64 session_total, const char *helpline, | 564 | u64 session_total, const char *helpline, |
| 518 | const char *input_name) | 565 | const char *input_name) |
| 519 | { | 566 | { |
| 520 | struct newtExitStruct es; | 567 | struct newtExitStruct es; |
| 521 | bool dso_filtered = false; | 568 | bool dso_filtered = false, thread_filtered = false; |
| 522 | int err = -1; | 569 | int err = -1; |
| 523 | struct hist_browser *browser = hist_browser__new(); | 570 | struct hist_browser *browser = hist_browser__new(); |
| 524 | 571 | ||
| @@ -531,9 +578,10 @@ int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | |||
| 531 | goto out; | 578 | goto out; |
| 532 | 579 | ||
| 533 | while (1) { | 580 | while (1) { |
| 581 | const struct thread *thread; | ||
| 534 | char *options[16]; | 582 | char *options[16]; |
| 535 | int nr_options = 0, choice = 0, i, | 583 | int nr_options = 0, choice = 0, i, |
| 536 | annotate = -2, zoom_dso = -2; | 584 | annotate = -2, zoom_dso = -2, zoom_thread = -2; |
| 537 | 585 | ||
| 538 | newtFormRun(browser->form, &es); | 586 | newtFormRun(browser->form, &es); |
| 539 | if (es.reason == NEWT_EXIT_HOTKEY) { | 587 | if (es.reason == NEWT_EXIT_HOTKEY) { |
| @@ -561,6 +609,13 @@ int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | |||
| 561 | browser->selection->map->dso->short_name)) > 0) | 609 | browser->selection->map->dso->short_name)) > 0) |
| 562 | zoom_dso = nr_options++; | 610 | zoom_dso = nr_options++; |
| 563 | 611 | ||
| 612 | thread = hist_browser__selected_thread(browser); | ||
| 613 | if (thread != NULL && | ||
| 614 | asprintf(&options[nr_options], "Zoom %s %s(%d) thread", | ||
| 615 | (thread_filtered ? "out of" : "into"), | ||
| 616 | (thread->comm_set ? thread->comm : ""), thread->pid) > 0) | ||
| 617 | zoom_thread = nr_options++; | ||
| 618 | |||
| 564 | options[nr_options++] = (char *)"Exit"; | 619 | options[nr_options++] = (char *)"Exit"; |
| 565 | 620 | ||
| 566 | choice = popup_menu(nr_options, options); | 621 | choice = popup_menu(nr_options, options); |
| @@ -570,6 +625,9 @@ int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | |||
| 570 | 625 | ||
| 571 | if (choice == nr_options - 1) | 626 | if (choice == nr_options - 1) |
| 572 | break; | 627 | break; |
| 628 | |||
| 629 | if (choice == -1) | ||
| 630 | continue; | ||
| 573 | do_annotate: | 631 | do_annotate: |
| 574 | if (choice == annotate) { | 632 | if (choice == annotate) { |
| 575 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { | 633 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { |
| @@ -581,13 +639,21 @@ do_annotate: | |||
| 581 | } | 639 | } |
| 582 | map_symbol__annotate_browser(browser->selection, | 640 | map_symbol__annotate_browser(browser->selection, |
| 583 | input_name); | 641 | input_name); |
| 584 | } if (choice == zoom_dso) { | 642 | } else if (choice == zoom_dso) { |
| 585 | hists__filter_by_dso(hists, | 643 | nr_hists = hists__filter_by_dso(hists, |
| 586 | dso_filtered ? NULL : browser->selection->map->dso, | 644 | (dso_filtered ? NULL : |
| 587 | &session_total); | 645 | browser->selection->map->dso), |
| 646 | &session_total); | ||
| 588 | dso_filtered = !dso_filtered; | 647 | dso_filtered = !dso_filtered; |
| 589 | if (hist_browser__populate(browser, hists, nr_hists, session_total) < 0) | 648 | if (hist_browser__populate(browser, hists, nr_hists, session_total) < 0) |
| 590 | goto out; | 649 | goto out; |
| 650 | } else if (choice == zoom_thread) { | ||
| 651 | nr_hists = hists__filter_by_thread(hists, | ||
| 652 | (thread_filtered ? NULL : thread), | ||
| 653 | &session_total); | ||
| 654 | thread_filtered = !thread_filtered; | ||
| 655 | if (hist_browser__populate(browser, hists, nr_hists, session_total) < 0) | ||
| 656 | goto out; | ||
| 591 | } | 657 | } |
| 592 | } | 658 | } |
| 593 | err = 0; | 659 | err = 0; |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index dce79d33e339..6d7b4be70609 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -44,11 +44,16 @@ extern enum sort_type sort__first_dimension; | |||
| 44 | struct hist_entry { | 44 | struct hist_entry { |
| 45 | struct rb_node rb_node; | 45 | struct rb_node rb_node; |
| 46 | u64 count; | 46 | u64 count; |
| 47 | struct thread *thread; | 47 | /* |
| 48 | * XXX WARNING! | ||
| 49 | * thread _has_ to come after ms, see | ||
| 50 | * hist_browser__selected_thread in util/newt.c | ||
| 51 | */ | ||
| 48 | struct map_symbol ms; | 52 | struct map_symbol ms; |
| 53 | struct thread *thread; | ||
| 49 | u64 ip; | 54 | u64 ip; |
| 50 | char level; | 55 | char level; |
| 51 | bool filtered; | 56 | u8 filtered; |
| 52 | struct symbol *parent; | 57 | struct symbol *parent; |
| 53 | union { | 58 | union { |
| 54 | unsigned long position; | 59 | unsigned long position; |
