diff options
Diffstat (limited to 'tools/perf/util/hist.c')
-rw-r--r-- | tools/perf/util/hist.c | 184 |
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 | |||
847 | static 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 | |||
857 | int 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 | |||
888 | static 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 | |||
900 | void objdump_line__free(struct objdump_line *self) | ||
901 | { | ||
902 | free(self->line); | ||
903 | free(self); | ||
904 | } | ||
905 | |||
906 | static void objdump__add_line(struct list_head *head, struct objdump_line *line) | ||
907 | { | ||
908 | list_add_tail(&line->node, head); | ||
909 | } | ||
910 | |||
911 | struct 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 | |||
921 | static 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 | |||
979 | int 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 | } | ||