aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/ui/hist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/ui/hist.c')
-rw-r--r--tools/perf/ui/hist.c262
1 files changed, 182 insertions, 80 deletions
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index bf2a66e254ea..3baeaa6e71b5 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -5,6 +5,7 @@
5#include "../util/util.h" 5#include "../util/util.h"
6#include "../util/sort.h" 6#include "../util/sort.h"
7#include "../util/evsel.h" 7#include "../util/evsel.h"
8#include "../util/evlist.h"
8 9
9/* hist period print (hpp) functions */ 10/* hist period print (hpp) functions */
10 11
@@ -371,7 +372,20 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
371 return 0; 372 return 0;
372} 373}
373 374
374#define HPP__COLOR_PRINT_FNS(_name, _fn) \ 375static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a)
376{
377 return a->header == hpp__header_fn;
378}
379
380static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
381{
382 if (!perf_hpp__is_hpp_entry(a) || !perf_hpp__is_hpp_entry(b))
383 return false;
384
385 return a->idx == b->idx;
386}
387
388#define HPP__COLOR_PRINT_FNS(_name, _fn, _idx) \
375 { \ 389 { \
376 .name = _name, \ 390 .name = _name, \
377 .header = hpp__header_fn, \ 391 .header = hpp__header_fn, \
@@ -381,9 +395,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
381 .cmp = hpp__nop_cmp, \ 395 .cmp = hpp__nop_cmp, \
382 .collapse = hpp__nop_cmp, \ 396 .collapse = hpp__nop_cmp, \
383 .sort = hpp__sort_ ## _fn, \ 397 .sort = hpp__sort_ ## _fn, \
398 .idx = PERF_HPP__ ## _idx, \
399 .equal = hpp__equal, \
384 } 400 }
385 401
386#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn) \ 402#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn, _idx) \
387 { \ 403 { \
388 .name = _name, \ 404 .name = _name, \
389 .header = hpp__header_fn, \ 405 .header = hpp__header_fn, \
@@ -393,9 +409,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
393 .cmp = hpp__nop_cmp, \ 409 .cmp = hpp__nop_cmp, \
394 .collapse = hpp__nop_cmp, \ 410 .collapse = hpp__nop_cmp, \
395 .sort = hpp__sort_ ## _fn, \ 411 .sort = hpp__sort_ ## _fn, \
412 .idx = PERF_HPP__ ## _idx, \
413 .equal = hpp__equal, \
396 } 414 }
397 415
398#define HPP__PRINT_FNS(_name, _fn) \ 416#define HPP__PRINT_FNS(_name, _fn, _idx) \
399 { \ 417 { \
400 .name = _name, \ 418 .name = _name, \
401 .header = hpp__header_fn, \ 419 .header = hpp__header_fn, \
@@ -404,22 +422,25 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
404 .cmp = hpp__nop_cmp, \ 422 .cmp = hpp__nop_cmp, \
405 .collapse = hpp__nop_cmp, \ 423 .collapse = hpp__nop_cmp, \
406 .sort = hpp__sort_ ## _fn, \ 424 .sort = hpp__sort_ ## _fn, \
425 .idx = PERF_HPP__ ## _idx, \
426 .equal = hpp__equal, \
407 } 427 }
408 428
409struct perf_hpp_fmt perf_hpp__format[] = { 429struct perf_hpp_fmt perf_hpp__format[] = {
410 HPP__COLOR_PRINT_FNS("Overhead", overhead), 430 HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD),
411 HPP__COLOR_PRINT_FNS("sys", overhead_sys), 431 HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS),
412 HPP__COLOR_PRINT_FNS("usr", overhead_us), 432 HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US),
413 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys), 433 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS),
414 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us), 434 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US),
415 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc), 435 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC),
416 HPP__PRINT_FNS("Samples", samples), 436 HPP__PRINT_FNS("Samples", samples, SAMPLES),
417 HPP__PRINT_FNS("Period", period) 437 HPP__PRINT_FNS("Period", period, PERIOD)
418}; 438};
419 439
420LIST_HEAD(perf_hpp__list); 440struct perf_hpp_list perf_hpp_list = {
421LIST_HEAD(perf_hpp__sort_list); 441 .fields = LIST_HEAD_INIT(perf_hpp_list.fields),
422 442 .sorts = LIST_HEAD_INIT(perf_hpp_list.sorts),
443};
423 444
424#undef HPP__COLOR_PRINT_FNS 445#undef HPP__COLOR_PRINT_FNS
425#undef HPP__COLOR_ACC_PRINT_FNS 446#undef HPP__COLOR_ACC_PRINT_FNS
@@ -485,63 +506,60 @@ void perf_hpp__init(void)
485 hpp_dimension__add_output(PERF_HPP__PERIOD); 506 hpp_dimension__add_output(PERF_HPP__PERIOD);
486} 507}
487 508
488void perf_hpp__column_register(struct perf_hpp_fmt *format) 509void perf_hpp_list__column_register(struct perf_hpp_list *list,
510 struct perf_hpp_fmt *format)
489{ 511{
490 list_add_tail(&format->list, &perf_hpp__list); 512 list_add_tail(&format->list, &list->fields);
491} 513}
492 514
493void perf_hpp__column_unregister(struct perf_hpp_fmt *format) 515void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
516 struct perf_hpp_fmt *format)
494{ 517{
495 list_del(&format->list); 518 list_add_tail(&format->sort_list, &list->sorts);
496} 519}
497 520
498void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) 521void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
499{
500 list_add_tail(&format->sort_list, &perf_hpp__sort_list);
501}
502
503void perf_hpp__column_enable(unsigned col)
504{
505 BUG_ON(col >= PERF_HPP__MAX_INDEX);
506 perf_hpp__column_register(&perf_hpp__format[col]);
507}
508
509void perf_hpp__column_disable(unsigned col)
510{ 522{
511 BUG_ON(col >= PERF_HPP__MAX_INDEX); 523 list_del(&format->list);
512 perf_hpp__column_unregister(&perf_hpp__format[col]);
513} 524}
514 525
515void perf_hpp__cancel_cumulate(void) 526void perf_hpp__cancel_cumulate(void)
516{ 527{
528 struct perf_hpp_fmt *fmt, *acc, *ovh, *tmp;
529
517 if (is_strict_order(field_order)) 530 if (is_strict_order(field_order))
518 return; 531 return;
519 532
520 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); 533 ovh = &perf_hpp__format[PERF_HPP__OVERHEAD];
521 perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead"; 534 acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC];
535
536 perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) {
537 if (acc->equal(acc, fmt)) {
538 perf_hpp__column_unregister(fmt);
539 continue;
540 }
541
542 if (ovh->equal(ovh, fmt))
543 fmt->name = "Overhead";
544 }
522} 545}
523 546
524void perf_hpp__setup_output_field(void) 547static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
548{
549 return a->equal && a->equal(a, b);
550}
551
552void perf_hpp__setup_output_field(struct perf_hpp_list *list)
525{ 553{
526 struct perf_hpp_fmt *fmt; 554 struct perf_hpp_fmt *fmt;
527 555
528 /* append sort keys to output field */ 556 /* append sort keys to output field */
529 perf_hpp__for_each_sort_list(fmt) { 557 perf_hpp_list__for_each_sort_list(list, fmt) {
530 if (!list_empty(&fmt->list)) 558 struct perf_hpp_fmt *pos;
531 continue;
532
533 /*
534 * sort entry fields are dynamically created,
535 * so they can share a same sort key even though
536 * the list is empty.
537 */
538 if (perf_hpp__is_sort_entry(fmt)) {
539 struct perf_hpp_fmt *pos;
540 559
541 perf_hpp__for_each_format(pos) { 560 perf_hpp_list__for_each_format(list, pos) {
542 if (perf_hpp__same_sort_entry(pos, fmt)) 561 if (fmt_equal(fmt, pos))
543 goto next; 562 goto next;
544 }
545 } 563 }
546 564
547 perf_hpp__column_register(fmt); 565 perf_hpp__column_register(fmt);
@@ -550,27 +568,17 @@ next:
550 } 568 }
551} 569}
552 570
553void perf_hpp__append_sort_keys(void) 571void perf_hpp__append_sort_keys(struct perf_hpp_list *list)
554{ 572{
555 struct perf_hpp_fmt *fmt; 573 struct perf_hpp_fmt *fmt;
556 574
557 /* append output fields to sort keys */ 575 /* append output fields to sort keys */
558 perf_hpp__for_each_format(fmt) { 576 perf_hpp_list__for_each_format(list, fmt) {
559 if (!list_empty(&fmt->sort_list)) 577 struct perf_hpp_fmt *pos;
560 continue;
561
562 /*
563 * sort entry fields are dynamically created,
564 * so they can share a same sort key even though
565 * the list is empty.
566 */
567 if (perf_hpp__is_sort_entry(fmt)) {
568 struct perf_hpp_fmt *pos;
569 578
570 perf_hpp__for_each_sort_list(pos) { 579 perf_hpp_list__for_each_sort_list(list, pos) {
571 if (perf_hpp__same_sort_entry(pos, fmt)) 580 if (fmt_equal(fmt, pos))
572 goto next; 581 goto next;
573 }
574 } 582 }
575 583
576 perf_hpp__register_sort_field(fmt); 584 perf_hpp__register_sort_field(fmt);
@@ -579,20 +587,29 @@ next:
579 } 587 }
580} 588}
581 589
582void perf_hpp__reset_output_field(void) 590
591static void fmt_free(struct perf_hpp_fmt *fmt)
592{
593 if (fmt->free)
594 fmt->free(fmt);
595}
596
597void perf_hpp__reset_output_field(struct perf_hpp_list *list)
583{ 598{
584 struct perf_hpp_fmt *fmt, *tmp; 599 struct perf_hpp_fmt *fmt, *tmp;
585 600
586 /* reset output fields */ 601 /* reset output fields */
587 perf_hpp__for_each_format_safe(fmt, tmp) { 602 perf_hpp_list__for_each_format_safe(list, fmt, tmp) {
588 list_del_init(&fmt->list); 603 list_del_init(&fmt->list);
589 list_del_init(&fmt->sort_list); 604 list_del_init(&fmt->sort_list);
605 fmt_free(fmt);
590 } 606 }
591 607
592 /* reset sort keys */ 608 /* reset sort keys */
593 perf_hpp__for_each_sort_list_safe(fmt, tmp) { 609 perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) {
594 list_del_init(&fmt->list); 610 list_del_init(&fmt->list);
595 list_del_init(&fmt->sort_list); 611 list_del_init(&fmt->sort_list);
612 fmt_free(fmt);
596 } 613 }
597} 614}
598 615
@@ -606,7 +623,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
606 bool first = true; 623 bool first = true;
607 struct perf_hpp dummy_hpp; 624 struct perf_hpp dummy_hpp;
608 625
609 perf_hpp__for_each_format(fmt) { 626 hists__for_each_format(hists, fmt) {
610 if (perf_hpp__should_skip(fmt, hists)) 627 if (perf_hpp__should_skip(fmt, hists))
611 continue; 628 continue;
612 629
@@ -624,22 +641,39 @@ unsigned int hists__sort_list_width(struct hists *hists)
624 return ret; 641 return ret;
625} 642}
626 643
627void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) 644unsigned int hists__overhead_width(struct hists *hists)
628{ 645{
629 int idx; 646 struct perf_hpp_fmt *fmt;
630 647 int ret = 0;
631 if (perf_hpp__is_sort_entry(fmt)) 648 bool first = true;
632 return perf_hpp__reset_sort_width(fmt, hists); 649 struct perf_hpp dummy_hpp;
633 650
634 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { 651 hists__for_each_format(hists, fmt) {
635 if (fmt == &perf_hpp__format[idx]) 652 if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
636 break; 653 break;
654
655 if (first)
656 first = false;
657 else
658 ret += 2;
659
660 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
637 } 661 }
638 662
639 if (idx == PERF_HPP__MAX_INDEX) 663 return ret;
664}
665
666void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
667{
668 if (perf_hpp__is_sort_entry(fmt))
669 return perf_hpp__reset_sort_width(fmt, hists);
670
671 if (perf_hpp__is_dynamic_entry(fmt))
640 return; 672 return;
641 673
642 switch (idx) { 674 BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);
675
676 switch (fmt->idx) {
643 case PERF_HPP__OVERHEAD: 677 case PERF_HPP__OVERHEAD:
644 case PERF_HPP__OVERHEAD_SYS: 678 case PERF_HPP__OVERHEAD_SYS:
645 case PERF_HPP__OVERHEAD_US: 679 case PERF_HPP__OVERHEAD_US:
@@ -667,7 +701,7 @@ void perf_hpp__set_user_width(const char *width_list_str)
667 struct perf_hpp_fmt *fmt; 701 struct perf_hpp_fmt *fmt;
668 const char *ptr = width_list_str; 702 const char *ptr = width_list_str;
669 703
670 perf_hpp__for_each_format(fmt) { 704 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
671 char *p; 705 char *p;
672 706
673 int len = strtol(ptr, &p, 10); 707 int len = strtol(ptr, &p, 10);
@@ -679,3 +713,71 @@ void perf_hpp__set_user_width(const char *width_list_str)
679 break; 713 break;
680 } 714 }
681} 715}
716
717static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt)
718{
719 struct perf_hpp_list_node *node = NULL;
720 struct perf_hpp_fmt *fmt_copy;
721 bool found = false;
722 bool skip = perf_hpp__should_skip(fmt, hists);
723
724 list_for_each_entry(node, &hists->hpp_formats, list) {
725 if (node->level == fmt->level) {
726 found = true;
727 break;
728 }
729 }
730
731 if (!found) {
732 node = malloc(sizeof(*node));
733 if (node == NULL)
734 return -1;
735
736 node->skip = skip;
737 node->level = fmt->level;
738 perf_hpp_list__init(&node->hpp);
739
740 hists->nr_hpp_node++;
741 list_add_tail(&node->list, &hists->hpp_formats);
742 }
743
744 fmt_copy = perf_hpp_fmt__dup(fmt);
745 if (fmt_copy == NULL)
746 return -1;
747
748 if (!skip)
749 node->skip = false;
750
751 list_add_tail(&fmt_copy->list, &node->hpp.fields);
752 list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts);
753
754 return 0;
755}
756
757int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
758 struct perf_evlist *evlist)
759{
760 struct perf_evsel *evsel;
761 struct perf_hpp_fmt *fmt;
762 struct hists *hists;
763 int ret;
764
765 if (!symbol_conf.report_hierarchy)
766 return 0;
767
768 evlist__for_each(evlist, evsel) {
769 hists = evsel__hists(evsel);
770
771 perf_hpp_list__for_each_sort_list(list, fmt) {
772 if (perf_hpp__is_dynamic_entry(fmt) &&
773 !perf_hpp__defined_dynamic_entry(fmt, hists))
774 continue;
775
776 ret = add_hierarchy_fmt(hists, fmt);
777 if (ret < 0)
778 return ret;
779 }
780 }
781
782 return 0;
783}