aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation/perf_counter/builtin-report.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-05-27 14:20:24 -0400
committerIngo Molnar <mingo@elte.hu>2009-05-27 15:44:13 -0400
commite7fb08b1d06a6b37263c765205de5614a2273aeb (patch)
treec8548e6b58a386325f11f9c069792136d2f625a8 /Documentation/perf_counter/builtin-report.c
parent450aaa2b2a1b006870ba68251fbb40b2387caade (diff)
perf_counter: tools: report: Rework histogram code
In preparation for configurable sorting, rework the histgram code a bit. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: John Kacur <jkacur@redhat.com> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <20090527182100.796410098@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation/perf_counter/builtin-report.c')
-rw-r--r--Documentation/perf_counter/builtin-report.c294
1 files changed, 143 insertions, 151 deletions
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c
index 3e87cbd3045a..276256439b78 100644
--- a/Documentation/perf_counter/builtin-report.c
+++ b/Documentation/perf_counter/builtin-report.c
@@ -597,71 +597,9 @@ struct thread;
597 597
598static const char *thread__name(struct thread *self, char *bf, size_t size); 598static const char *thread__name(struct thread *self, char *bf, size_t size);
599 599
600struct symhist {
601 struct rb_node rb_node;
602 struct dso *dso;
603 struct symbol *sym;
604 struct thread *thread;
605 uint64_t ip;
606 uint32_t count;
607 char level;
608};
609
610static struct symhist *symhist__new(struct symbol *sym, uint64_t ip,
611 struct thread *thread, struct dso *dso,
612 char level)
613{
614 struct symhist *self = malloc(sizeof(*self));
615
616 if (self != NULL) {
617 self->sym = sym;
618 self->thread = thread;
619 self->ip = ip;
620 self->dso = dso;
621 self->level = level;
622 self->count = 1;
623 }
624
625 return self;
626}
627
628static void symhist__inc(struct symhist *self)
629{
630 ++self->count;
631}
632
633static size_t
634symhist__fprintf(struct symhist *self, uint64_t total_samples, FILE *fp)
635{
636 char bf[32];
637 size_t ret;
638
639 if (total_samples)
640 ret = fprintf(fp, "%5.2f%% ", (self->count * 100.0) / total_samples);
641 else
642 ret = fprintf(fp, "%12d ", self->count);
643
644 ret += fprintf(fp, "%14s [%c] ",
645 thread__name(self->thread, bf, sizeof(bf)),
646 self->level);
647
648 if (verbose)
649 ret += fprintf(fp, "%#018llx ", (unsigned long long)self->ip);
650
651 if (self->level != '.')
652 ret += fprintf(fp, "%s\n",
653 self->sym ? self->sym->name : "<unknown>");
654 else
655 ret += fprintf(fp, "%s: %s\n",
656 self->dso ? self->dso->name : "<unknown>",
657 self->sym ? self->sym->name : "<unknown>");
658 return ret;
659}
660
661struct thread { 600struct thread {
662 struct rb_node rb_node; 601 struct rb_node rb_node;
663 struct list_head maps; 602 struct list_head maps;
664 struct rb_root symhists;
665 pid_t pid; 603 pid_t pid;
666 char *comm; 604 char *comm;
667}; 605};
@@ -683,67 +621,17 @@ static struct thread *thread__new(pid_t pid)
683 self->pid = pid; 621 self->pid = pid;
684 self->comm = NULL; 622 self->comm = NULL;
685 INIT_LIST_HEAD(&self->maps); 623 INIT_LIST_HEAD(&self->maps);
686 self->symhists = RB_ROOT;
687 } 624 }
688 625
689 return self; 626 return self;
690} 627}
691 628
692static int thread__symbol_incnew(struct thread *self, struct symbol *sym,
693 uint64_t ip, struct dso *dso, char level)
694{
695 struct rb_node **p = &self->symhists.rb_node;
696 struct rb_node *parent = NULL;
697 struct symhist *sh;
698
699 while (*p != NULL) {
700 uint64_t start;
701
702 parent = *p;
703 sh = rb_entry(parent, struct symhist, rb_node);
704
705 if (sh->sym == sym || ip == sh->ip) {
706 symhist__inc(sh);
707 return 0;
708 }
709
710 /* Handle unresolved symbols too */
711 start = !sh->sym ? sh->ip : sh->sym->start;
712
713 if (ip < start)
714 p = &(*p)->rb_left;
715 else
716 p = &(*p)->rb_right;
717 }
718
719 sh = symhist__new(sym, ip, self, dso, level);
720 if (sh == NULL)
721 return -ENOMEM;
722 rb_link_node(&sh->rb_node, parent, p);
723 rb_insert_color(&sh->rb_node, &self->symhists);
724 return 0;
725}
726
727static int thread__set_comm(struct thread *self, const char *comm) 629static int thread__set_comm(struct thread *self, const char *comm)
728{ 630{
729 self->comm = strdup(comm); 631 self->comm = strdup(comm);
730 return self->comm ? 0 : -ENOMEM; 632 return self->comm ? 0 : -ENOMEM;
731} 633}
732 634
733static size_t thread__fprintf(struct thread *self, FILE *fp)
734{
735 int ret = fprintf(fp, "thread: %d %s\n", self->pid, self->comm);
736 struct rb_node *nd;
737
738 for (nd = rb_first(&self->symhists); nd; nd = rb_next(nd)) {
739 struct symhist *pos = rb_entry(nd, struct symhist, rb_node);
740
741 ret += symhist__fprintf(pos, 0, fp);
742 }
743
744 return ret;
745}
746
747static struct rb_root threads; 635static struct rb_root threads;
748 636
749static struct thread *threads__findnew(pid_t pid) 637static struct thread *threads__findnew(pid_t pid)
@@ -792,70 +680,172 @@ static struct map *thread__find_map(struct thread *self, uint64_t ip)
792 return NULL; 680 return NULL;
793} 681}
794 682
795static void threads__fprintf(FILE *fp) 683/*
684 * histogram, sorted on item, collects counts
685 */
686
687static struct rb_root hist;
688
689struct hist_entry {
690 struct rb_node rb_node;
691
692 struct thread *thread;
693 struct map *map;
694 struct dso *dso;
695 struct symbol *sym;
696 uint64_t ip;
697 char level;
698
699 uint32_t count;
700};
701
702static int64_t
703hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
704{
705 uint64_t ip_l, ip_r;
706 int cmp = right->thread->pid - left->thread->pid;
707
708 if (cmp)
709 return cmp;
710
711 if (left->sym == right->sym)
712 return 0;
713
714 ip_l = left->sym ? left->sym->start : left->ip;
715 ip_r = right->sym ? right->sym->start : right->ip;
716
717 return (int64_t)(ip_r - ip_l);
718}
719
720static int
721hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
722 struct symbol *sym, uint64_t ip, char level)
796{ 723{
797 struct rb_node *nd; 724 struct rb_node **p = &hist.rb_node;
798 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { 725 struct rb_node *parent = NULL;
799 struct thread *pos = rb_entry(nd, struct thread, rb_node); 726 struct hist_entry *he;
800 thread__fprintf(pos, fp); 727 struct hist_entry entry = {
728 .thread = thread,
729 .map = map,
730 .dso = dso,
731 .sym = sym,
732 .ip = ip,
733 .level = level,
734 .count = 1,
735 };
736 int cmp;
737
738 while (*p != NULL) {
739 parent = *p;
740 he = rb_entry(parent, struct hist_entry, rb_node);
741
742 cmp = hist_entry__cmp(&entry, he);
743
744 if (!cmp) {
745 he->count++;
746 return 0;
747 }
748
749 if (cmp < 0)
750 p = &(*p)->rb_left;
751 else
752 p = &(*p)->rb_right;
801 } 753 }
754
755 he = malloc(sizeof(*he));
756 if (!he)
757 return -ENOMEM;
758 *he = entry;
759 rb_link_node(&he->rb_node, parent, p);
760 rb_insert_color(&he->rb_node, &hist);
761
762 return 0;
802} 763}
803 764
804static struct rb_root global_symhists; 765static size_t
766hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
767{
768 char bf[32];
769 size_t ret;
770
771 if (total_samples) {
772 ret = fprintf(fp, "%5.2f%% ",
773 (self->count * 100.0) / total_samples);
774 } else
775 ret = fprintf(fp, "%12d ", self->count);
805 776
806static void threads__insert_symhist(struct symhist *sh) 777 ret += fprintf(fp, "%14s [%c] ",
778 thread__name(self->thread, bf, sizeof(bf)),
779 self->level);
780
781 if (verbose)
782 ret += fprintf(fp, "%#018llx ", (unsigned long long)self->ip);
783
784 if (self->level != '.')
785 ret += fprintf(fp, "%s\n",
786 self->sym ? self->sym->name : "<unknown>");
787 else
788 ret += fprintf(fp, "%s: %s\n",
789 self->dso ? self->dso->name : "<unknown>",
790 self->sym ? self->sym->name : "<unknown>");
791 return ret;
792}
793
794/*
795 * reverse the map, sort on count.
796 */
797
798static struct rb_root output_hists;
799
800static void output__insert_entry(struct hist_entry *he)
807{ 801{
808 struct rb_node **p = &global_symhists.rb_node; 802 struct rb_node **p = &output_hists.rb_node;
809 struct rb_node *parent = NULL; 803 struct rb_node *parent = NULL;
810 struct symhist *iter; 804 struct hist_entry *iter;
811 805
812 while (*p != NULL) { 806 while (*p != NULL) {
813 parent = *p; 807 parent = *p;
814 iter = rb_entry(parent, struct symhist, rb_node); 808 iter = rb_entry(parent, struct hist_entry, rb_node);
815 809
816 /* Reverse order */ 810 if (he->count > iter->count)
817 if (sh->count > iter->count)
818 p = &(*p)->rb_left; 811 p = &(*p)->rb_left;
819 else 812 else
820 p = &(*p)->rb_right; 813 p = &(*p)->rb_right;
821 } 814 }
822 815
823 rb_link_node(&sh->rb_node, parent, p); 816 rb_link_node(&he->rb_node, parent, p);
824 rb_insert_color(&sh->rb_node, &global_symhists); 817 rb_insert_color(&he->rb_node, &output_hists);
825} 818}
826 819
827static void threads__sort_symhists(void) 820static void output__resort(void)
828{ 821{
829 struct rb_node *nd; 822 struct rb_node *next = rb_first(&hist);
830 823 struct hist_entry *n;
831 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
832 struct thread *thread = rb_entry(nd, struct thread, rb_node);
833 struct rb_node *next = rb_first(&thread->symhists);
834 824
835 while (next) { 825 while (next) {
836 struct symhist *n = rb_entry(next, struct symhist, 826 n = rb_entry(next, struct hist_entry, rb_node);
837 rb_node); 827 next = rb_next(&n->rb_node);
838 next = rb_next(&n->rb_node);
839 rb_erase(&n->rb_node, &thread->symhists);
840 threads__insert_symhist(n);
841 }
842 828
829 rb_erase(&n->rb_node, &hist);
830 output__insert_entry(n);
843 } 831 }
844} 832}
845 833
846static size_t threads__symhists_fprintf(uint64_t total_samples, FILE *fp) 834static size_t output__fprintf(FILE *fp, uint64_t total_samples)
847{ 835{
836 struct hist_entry *pos;
848 struct rb_node *nd; 837 struct rb_node *nd;
849 size_t ret = 0; 838 size_t ret = 0;
850 839
851 for (nd = rb_first(&global_symhists); nd; nd = rb_next(nd)) { 840 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
852 struct symhist *pos = rb_entry(nd, struct symhist, rb_node); 841 pos = rb_entry(nd, struct hist_entry, rb_node);
853 ret += symhist__fprintf(pos, total_samples, fp); 842 ret += hist_entry__fprintf(fp, pos, total_samples);
854 } 843 }
855 844
856 return ret; 845 return ret;
857} 846}
858 847
848
859static int __cmd_report(void) 849static int __cmd_report(void)
860{ 850{
861 unsigned long offset = 0; 851 unsigned long offset = 0;
@@ -926,6 +916,7 @@ more:
926 struct dso *dso = NULL; 916 struct dso *dso = NULL;
927 struct thread *thread = threads__findnew(event->ip.pid); 917 struct thread *thread = threads__findnew(event->ip.pid);
928 uint64_t ip = event->ip.ip; 918 uint64_t ip = event->ip.ip;
919 struct map *map = NULL;
929 920
930 if (dump_trace) { 921 if (dump_trace) {
931 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 922 fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
@@ -945,9 +936,10 @@ more:
945 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 936 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
946 show = SHOW_KERNEL; 937 show = SHOW_KERNEL;
947 level = 'k'; 938 level = 'k';
939
948 dso = kernel_dso; 940 dso = kernel_dso;
941
949 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 942 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
950 struct map *map;
951 943
952 show = SHOW_USER; 944 show = SHOW_USER;
953 level = '.'; 945 level = '.';
@@ -957,6 +949,7 @@ more:
957 dso = map->dso; 949 dso = map->dso;
958 ip -= map->start + map->pgoff; 950 ip -= map->start + map->pgoff;
959 } 951 }
952
960 } else { 953 } else {
961 show = SHOW_HV; 954 show = SHOW_HV;
962 level = 'H'; 955 level = 'H';
@@ -965,8 +958,9 @@ more:
965 if (show & show_mask) { 958 if (show & show_mask) {
966 struct symbol *sym = dso__find_symbol(dso, ip); 959 struct symbol *sym = dso__find_symbol(dso, ip);
967 960
968 if (thread__symbol_incnew(thread, sym, ip, dso, level)) { 961 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
969 fprintf(stderr, "problem incrementing symbol count, bailing out\n"); 962 fprintf(stderr,
963 "problem incrementing symbol count, bailing out\n");
970 goto done; 964 goto done;
971 } 965 }
972 } 966 }
@@ -1050,13 +1044,11 @@ done:
1050 return 0; 1044 return 0;
1051 } 1045 }
1052 1046
1053 if (verbose >= 2) { 1047 if (verbose >= 2)
1054 dsos__fprintf(stdout); 1048 dsos__fprintf(stdout);
1055 threads__fprintf(stdout);
1056 }
1057 1049
1058 threads__sort_symhists(); 1050 output__resort();
1059 threads__symhists_fprintf(total, stdout); 1051 output__fprintf(stdout, total);
1060 1052
1061 return rc; 1053 return rc;
1062} 1054}