aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r--tools/perf/util/hist.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index e34fd248067d..451d2e45d843 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -784,3 +784,246 @@ print_entries:
784 784
785 return ret; 785 return ret;
786} 786}
787
788enum hist_filter {
789 HIST_FILTER__DSO,
790 HIST_FILTER__THREAD,
791};
792
793void hists__filter_by_dso(struct hists *self, const struct dso *dso)
794{
795 struct rb_node *nd;
796
797 self->nr_entries = self->stats.total = 0;
798 self->max_sym_namelen = 0;
799
800 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
801 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
802
803 if (symbol_conf.exclude_other && !h->parent)
804 continue;
805
806 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
807 h->filtered |= (1 << HIST_FILTER__DSO);
808 continue;
809 }
810
811 h->filtered &= ~(1 << HIST_FILTER__DSO);
812 if (!h->filtered) {
813 ++self->nr_entries;
814 self->stats.total += h->count;
815 if (h->ms.sym &&
816 self->max_sym_namelen < h->ms.sym->namelen)
817 self->max_sym_namelen = h->ms.sym->namelen;
818 }
819 }
820}
821
822void hists__filter_by_thread(struct hists *self, const struct thread *thread)
823{
824 struct rb_node *nd;
825
826 self->nr_entries = self->stats.total = 0;
827 self->max_sym_namelen = 0;
828
829 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
830 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
831
832 if (thread != NULL && h->thread != thread) {
833 h->filtered |= (1 << HIST_FILTER__THREAD);
834 continue;
835 }
836 h->filtered &= ~(1 << HIST_FILTER__THREAD);
837 if (!h->filtered) {
838 ++self->nr_entries;
839 self->stats.total += h->count;
840 if (h->ms.sym &&
841 self->max_sym_namelen < h->ms.sym->namelen)
842 self->max_sym_namelen = h->ms.sym->namelen;
843 }
844 }
845}
846
847static int symbol__alloc_hist(struct symbol *self)
848{
849 struct sym_priv *priv = symbol__priv(self);
850 const int size = (sizeof(*priv->hist) +
851 (self->end - self->start) * sizeof(u64));
852
853 priv->hist = zalloc(size);
854 return priv->hist == NULL ? -1 : 0;
855}
856
857int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
858{
859 unsigned int sym_size, offset;
860 struct symbol *sym = self->ms.sym;
861 struct sym_priv *priv;
862 struct sym_hist *h;
863
864 if (!sym || !self->ms.map)
865 return 0;
866
867 priv = symbol__priv(sym);
868 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
869 return -ENOMEM;
870
871 sym_size = sym->end - sym->start;
872 offset = ip - sym->start;
873
874 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
875
876 if (offset >= sym_size)
877 return 0;
878
879 h = priv->hist;
880 h->sum++;
881 h->ip[offset]++;
882
883 pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
884 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
885 return 0;
886}
887
888static struct objdump_line *objdump_line__new(s64 offset, char *line)
889{
890 struct objdump_line *self = malloc(sizeof(*self));
891
892 if (self != NULL) {
893 self->offset = offset;
894 self->line = line;
895 }
896
897 return self;
898}
899
900void objdump_line__free(struct objdump_line *self)
901{
902 free(self->line);
903 free(self);
904}
905
906static void objdump__add_line(struct list_head *head, struct objdump_line *line)
907{
908 list_add_tail(&line->node, head);
909}
910
911struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
912 struct objdump_line *pos)
913{
914 list_for_each_entry_continue(pos, head, node)
915 if (pos->offset >= 0)
916 return pos;
917
918 return NULL;
919}
920
921static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
922 struct list_head *head)
923{
924 struct symbol *sym = self->ms.sym;
925 struct objdump_line *objdump_line;
926 char *line = NULL, *tmp, *tmp2, *c;
927 size_t line_len;
928 s64 line_ip, offset = -1;
929
930 if (getline(&line, &line_len, file) < 0)
931 return -1;
932
933 if (!line)
934 return -1;
935
936 while (line_len != 0 && isspace(line[line_len - 1]))
937 line[--line_len] = '\0';
938
939 c = strchr(line, '\n');
940 if (c)
941 *c = 0;
942
943 line_ip = -1;
944
945 /*
946 * Strip leading spaces:
947 */
948 tmp = line;
949 while (*tmp) {
950 if (*tmp != ' ')
951 break;
952 tmp++;
953 }
954
955 if (*tmp) {
956 /*
957 * Parse hexa addresses followed by ':'
958 */
959 line_ip = strtoull(tmp, &tmp2, 16);
960 if (*tmp2 != ':')
961 line_ip = -1;
962 }
963
964 if (line_ip != -1) {
965 u64 start = map__rip_2objdump(self->ms.map, sym->start);
966 offset = line_ip - start;
967 }
968
969 objdump_line = objdump_line__new(offset, line);
970 if (objdump_line == NULL) {
971 free(line);
972 return -1;
973 }
974 objdump__add_line(head, objdump_line);
975
976 return 0;
977}
978
979int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
980{
981 struct symbol *sym = self->ms.sym;
982 struct map *map = self->ms.map;
983 struct dso *dso = map->dso;
984 const char *filename = dso->long_name;
985 char command[PATH_MAX * 2];
986 FILE *file;
987 u64 len;
988
989 if (!filename)
990 return -1;
991
992 if (dso->origin == DSO__ORIG_KERNEL) {
993 if (dso->annotate_warned)
994 return 0;
995 dso->annotate_warned = 1;
996 pr_err("Can't annotate %s: No vmlinux file was found in the "
997 "path:\n", sym->name);
998 vmlinux_path__fprintf(stderr);
999 return -1;
1000 }
1001
1002 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1003 filename, sym->name, map->unmap_ip(map, sym->start),
1004 map->unmap_ip(map, sym->end));
1005
1006 len = sym->end - sym->start;
1007
1008 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1009 dso, dso->long_name, sym, sym->name);
1010
1011 snprintf(command, sizeof(command),
1012 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand",
1013 map__rip_2objdump(map, sym->start),
1014 map__rip_2objdump(map, sym->end),
1015 filename, filename);
1016
1017 pr_debug("Executing: %s\n", command);
1018
1019 file = popen(command, "r");
1020 if (!file)
1021 return -1;
1022
1023 while (!feof(file))
1024 if (hist_entry__parse_objdump_line(self, file, head) < 0)
1025 break;
1026
1027 pclose(file);
1028 return 0;
1029}