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.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index baa55be64d9e..451d2e45d843 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -843,3 +843,187 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
843 } 843 }
844 } 844 }
845} 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}