aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-11-04 15:50:43 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-08 04:44:36 -0500
commit8d06367fa79c053a4a56a2ce0bb9e840f5da1236 (patch)
tree8ea057102e390c8411b77aeab7ea9c06ec0e0561 /tools/perf/util/symbol.c
parent2643ce11457a99a85c5bed8dd631e35968e6ca5a (diff)
perf symbols: Use the buildids if present
With this change 'perf record' will intercept PERF_RECORD_MMAP calls, creating a linked list of DSOs, then when the session finishes, it will traverse this list and read the buildids, stashing them at the end of the file and will set up a new feature bit in the header bitmask. 'perf report' will then notice this feature and populate the 'dsos' list and set the build ids. When reading the symtabs it will refuse to load from a file that doesn't have the same build id. This improves the reliability of the profiler output, as symbols and profiling data is more guaranteed to match. Example: [root@doppio ~]# perf report | head /home/acme/bin/perf with build id b1ea544ac3746e7538972548a09aadecc5753868 not found, continuing without symbols # Samples: 2621434559 # # Overhead Command Shared Object Symbol # ........ ............... ............................. ...... # 7.91% init [kernel] [k] read_hpet 7.64% init [kernel] [k] mwait_idle_with_hints 7.60% swapper [kernel] [k] read_hpet 7.60% swapper [kernel] [k] mwait_idle_with_hints 3.65% init [kernel] [k] 0xffffffffa02339d9 [root@doppio ~]# In this case the 'perf' binary was an older one, vanished, so its symbols probably wouldn't match or would cause subtly different (and misleading) output. Next patches will support the kernel as well, reading the build id notes for it and the modules from /sys. Another patch should also introduce a new plumbing command: 'perf list-buildids' that will then be used in porcelain that is distro specific to fetch -debuginfo packages where such buildids are present. This will in turn allow for one to run 'perf record' in one machine and 'perf report' in another. Future work on having the buildid sent directly from the kernel in the PERF_RECORD_MMAP event is needed to close races, as the DSO can be changed during a 'perf record' session, but this patch at least helps with non-corner cases and current/older kernels. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Frank Ch. Eigler <fche@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jason Baron <jbaron@redhat.com> Cc: Jim Keniston <jkenisto@us.ibm.com> Cc: K. Prasad <prasad@linux.vnet.ibm.com> Cc: Masami Hiramatsu <mhiramat@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Roland McGrath <roland@redhat.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <1257367843-26224-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c78
1 files changed, 56 insertions, 22 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index e7c7cdb851c2..a2e95ce1f223 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -121,7 +121,8 @@ struct dso *dso__new(const char *name)
121 self->find_symbol = dso__find_symbol; 121 self->find_symbol = dso__find_symbol;
122 self->slen_calculated = 0; 122 self->slen_calculated = 0;
123 self->origin = DSO__ORIG_NOT_FOUND; 123 self->origin = DSO__ORIG_NOT_FOUND;
124 self->loaded = false; 124 self->loaded = 0;
125 self->has_build_id = 0;
125 } 126 }
126 127
127 return self; 128 return self;
@@ -148,6 +149,12 @@ void dso__delete(struct dso *self)
148 free(self); 149 free(self);
149} 150}
150 151
152void dso__set_build_id(struct dso *self, void *build_id)
153{
154 memcpy(self->build_id, build_id, sizeof(self->build_id));
155 self->has_build_id = 1;
156}
157
151static void dso__insert_symbol(struct dso *self, struct symbol *sym) 158static void dso__insert_symbol(struct dso *self, struct symbol *sym)
152{ 159{
153 struct rb_node **p = &self->syms.rb_node; 160 struct rb_node **p = &self->syms.rb_node;
@@ -190,11 +197,30 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
190 return NULL; 197 return NULL;
191} 198}
192 199
193size_t dso__fprintf(struct dso *self, FILE *fp) 200int build_id__sprintf(u8 *self, int len, char *bf)
194{ 201{
195 size_t ret = fprintf(fp, "dso: %s\n", self->short_name); 202 char *bid = bf;
203 u8 *raw = self;
204 int i;
196 205
206 for (i = 0; i < len; ++i) {
207 sprintf(bid, "%02x", *raw);
208 ++raw;
209 bid += 2;
210 }
211
212 return raw - self;
213}
214
215size_t dso__fprintf(struct dso *self, FILE *fp)
216{
217 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
197 struct rb_node *nd; 218 struct rb_node *nd;
219 size_t ret;
220
221 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
222 ret = fprintf(fp, "dso: %s (%s)\n", self->short_name, sbuild_id);
223
198 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 224 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
199 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 225 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
200 ret += symbol__fprintf(pos, fp); 226 ret += symbol__fprintf(pos, fp);
@@ -825,8 +851,6 @@ out_close:
825 return err; 851 return err;
826} 852}
827 853
828#define BUILD_ID_SIZE 20
829
830int filename__read_build_id(const char *filename, void *bf, size_t size) 854int filename__read_build_id(const char *filename, void *bf, size_t size)
831{ 855{
832 int fd, err = -1; 856 int fd, err = -1;
@@ -845,7 +869,7 @@ int filename__read_build_id(const char *filename, void *bf, size_t size)
845 869
846 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 870 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
847 if (elf == NULL) { 871 if (elf == NULL) {
848 pr_err("%s: cannot read %s ELF file.\n", __func__, filename); 872 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
849 goto out_close; 873 goto out_close;
850 } 874 }
851 875
@@ -874,9 +898,9 @@ out:
874 898
875static char *dso__read_build_id(struct dso *self) 899static char *dso__read_build_id(struct dso *self)
876{ 900{
877 int i, len; 901 int len;
878 char *build_id = NULL, *bid; 902 char *build_id = NULL;
879 unsigned char rawbf[BUILD_ID_SIZE], *raw; 903 unsigned char rawbf[BUILD_ID_SIZE];
880 904
881 len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf)); 905 len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf));
882 if (len < 0) 906 if (len < 0)
@@ -885,15 +909,8 @@ static char *dso__read_build_id(struct dso *self)
885 build_id = malloc(len * 2 + 1); 909 build_id = malloc(len * 2 + 1);
886 if (build_id == NULL) 910 if (build_id == NULL)
887 goto out; 911 goto out;
888 bid = build_id;
889 912
890 raw = rawbf; 913 build_id__sprintf(rawbf, len, build_id);
891 for (i = 0; i < len; ++i) {
892 sprintf(bid, "%02x", *raw);
893 ++raw;
894 bid += 2;
895 }
896 pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id);
897out: 914out:
898 return build_id; 915 return build_id;
899} 916}
@@ -922,7 +939,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
922 int ret = -1; 939 int ret = -1;
923 int fd; 940 int fd;
924 941
925 self->loaded = true; 942 self->loaded = 1;
926 943
927 if (!name) 944 if (!name)
928 return -1; 945 return -1;
@@ -940,6 +957,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
940 957
941more: 958more:
942 do { 959 do {
960 int berr = 0;
961
943 self->origin++; 962 self->origin++;
944 switch (self->origin) { 963 switch (self->origin) {
945 case DSO__ORIG_FEDORA: 964 case DSO__ORIG_FEDORA:
@@ -956,8 +975,7 @@ more:
956 snprintf(name, size, 975 snprintf(name, size,
957 "/usr/lib/debug/.build-id/%.2s/%s.debug", 976 "/usr/lib/debug/.build-id/%.2s/%s.debug",
958 build_id, build_id + 2); 977 build_id, build_id + 2);
959 free(build_id); 978 goto compare_build_id;
960 break;
961 } 979 }
962 self->origin++; 980 self->origin++;
963 /* Fall thru */ 981 /* Fall thru */
@@ -969,6 +987,22 @@ more:
969 goto out; 987 goto out;
970 } 988 }
971 989
990 if (self->has_build_id) {
991 bool match;
992 build_id = malloc(BUILD_ID_SIZE);
993 if (build_id == NULL)
994 goto more;
995 berr = filename__read_build_id(name, build_id,
996 BUILD_ID_SIZE);
997compare_build_id:
998 match = berr > 0 && memcmp(build_id, self->build_id,
999 sizeof(self->build_id)) == 0;
1000 free(build_id);
1001 build_id = NULL;
1002 if (!match)
1003 goto more;
1004 }
1005
972 fd = open(name, O_RDONLY); 1006 fd = open(name, O_RDONLY);
973 } while (fd < 0); 1007 } while (fd < 0);
974 1008
@@ -1034,7 +1068,7 @@ static int dso__load_module_sym(struct dso *self, struct map *map,
1034{ 1068{
1035 int err = 0, fd = open(self->long_name, O_RDONLY); 1069 int err = 0, fd = open(self->long_name, O_RDONLY);
1036 1070
1037 self->loaded = true; 1071 self->loaded = 1;
1038 1072
1039 if (fd < 0) { 1073 if (fd < 0) {
1040 pr_err("%s: cannot open %s\n", __func__, self->long_name); 1074 pr_err("%s: cannot open %s\n", __func__, self->long_name);
@@ -1225,7 +1259,7 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1225{ 1259{
1226 int err, fd = open(vmlinux, O_RDONLY); 1260 int err, fd = open(vmlinux, O_RDONLY);
1227 1261
1228 self->loaded = true; 1262 self->loaded = 1;
1229 1263
1230 if (fd < 0) 1264 if (fd < 0)
1231 return -1; 1265 return -1;