aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/hist.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-05-11 22:18:06 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-05-11 22:23:20 -0400
commitef7b93a11904c6ba10604233d318d9e8ec88cddc (patch)
tree7ae6fa9cbe19be8fbbc18c8fdeb7edfdb7bdab60 /tools/perf/util/hist.c
parent3798ed7bc7ade26d3f59506cd06288615dfc7585 (diff)
perf report: Librarize the annotation code and use it in the newt browser
Now we don't anymore use popen to run 'perf annotate' for the selected symbol, instead we collect per address samplings when processing samples in 'perf report' if we're using the newt browser, then we use this data directly to do annotation. Done this way we can actually traverse the objdump_line objects directly, matching the addresses to the collected samples and colouring them appropriately using lower level slang routines. The new ui_browser class will be reused for the main, callchain aware, histogram browser, when it will be made generic and don't assume that the objects are always instances of the objdump_line class maintained using list_heads. Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
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}