aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
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
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')
-rw-r--r--tools/perf/util/data_map.c37
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/header.c10
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/map.c14
-rw-r--r--tools/perf/util/symbol.c78
-rw-r--r--tools/perf/util/symbol.h10
7 files changed, 133 insertions, 27 deletions
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index c458db9ede6d..00a9c114c8d0 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -70,6 +70,39 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
70 } 70 }
71} 71}
72 72
73static int perf_header__read_build_ids(const struct perf_header *self,
74 int input, off_t file_size)
75{
76 off_t offset = self->data_offset + self->data_size;
77 struct build_id_event bev;
78 char filename[PATH_MAX];
79 int err = -1;
80
81 if (lseek(input, offset, SEEK_SET) < 0)
82 return -1;
83
84 while (offset < file_size) {
85 struct dso *dso;
86 ssize_t len;
87
88 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
89 goto out;
90
91 len = bev.header.size - sizeof(bev);
92 if (read(input, filename, len) != len)
93 goto out;
94
95 dso = dsos__findnew(filename);
96 if (dso != NULL)
97 dso__set_build_id(dso, &bev.build_id);
98
99 offset += bev.header.size;
100 }
101 err = 0;
102out:
103 return err;
104}
105
73int mmap_dispatch_perf_file(struct perf_header **pheader, 106int mmap_dispatch_perf_file(struct perf_header **pheader,
74 const char *input_name, 107 const char *input_name,
75 int force, 108 int force,
@@ -130,6 +163,10 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
130 if (curr_handler->sample_type_check(sample_type) < 0) 163 if (curr_handler->sample_type_check(sample_type) < 0)
131 exit(-1); 164 exit(-1);
132 165
166 if (perf_header__has_feat(header, HEADER_BUILD_ID) &&
167 perf_header__read_build_ids(header, input, input_stat.st_size))
168 pr_debug("failed to read buildids, continuing...\n");
169
133 if (load_kernel(NULL) < 0) { 170 if (load_kernel(NULL) < 0) {
134 perror("failed to load kernel symbols"); 171 perror("failed to load kernel symbols");
135 return EXIT_FAILURE; 172 return EXIT_FAILURE;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 0a443bea68db..34c6fcb82d92 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -61,6 +61,13 @@ struct sample_event{
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64#define BUILD_ID_SIZE 20
65
66struct build_id_event {
67 struct perf_event_header header;
68 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
69 char filename[];
70};
64 71
65typedef union event_union { 72typedef union event_union {
66 struct perf_event_header header; 73 struct perf_event_header header;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7d26659b806c..050f543fd965 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -149,6 +149,16 @@ void perf_header__feat_trace_info(struct perf_header *header)
149 set_bit(HEADER_TRACE_INFO, header->adds_features); 149 set_bit(HEADER_TRACE_INFO, header->adds_features);
150} 150}
151 151
152void perf_header__set_feat(struct perf_header *self, int feat)
153{
154 set_bit(feat, self->adds_features);
155}
156
157bool perf_header__has_feat(const struct perf_header *self, int feat)
158{
159 return test_bit(feat, self->adds_features);
160}
161
152static void do_write(int fd, void *buf, size_t size) 162static void do_write(int fd, void *buf, size_t size)
153{ 163{
154 while (size) { 164 while (size) {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 2ea9dfb1236a..2f233c5db7e9 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -3,6 +3,7 @@
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
7 8
8#include <linux/bitmap.h> 9#include <linux/bitmap.h>
@@ -15,6 +16,7 @@ struct perf_header_attr {
15}; 16};
16 17
17#define HEADER_TRACE_INFO 1 18#define HEADER_TRACE_INFO 1
19#define HEADER_BUILD_ID 2
18 20
19#define HEADER_FEAT_BITS 256 21#define HEADER_FEAT_BITS 256
20 22
@@ -48,6 +50,8 @@ u64 perf_header__sample_type(struct perf_header *header);
48struct perf_event_attr * 50struct perf_event_attr *
49perf_header__find_attr(u64 id, struct perf_header *header); 51perf_header__find_attr(u64 id, struct perf_header *header);
50void perf_header__feat_trace_info(struct perf_header *header); 52void perf_header__feat_trace_info(struct perf_header *header);
53void perf_header__set_feat(struct perf_header *self, int feat);
54bool perf_header__has_feat(const struct perf_header *self, int feat);
51 55
52struct perf_header *perf_header__new(void); 56struct perf_header *perf_header__new(void);
53 57
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 33f868420d73..94ca95073c40 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -84,8 +84,18 @@ map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter)
84 int nr = dso__load(self->dso, self, filter); 84 int nr = dso__load(self->dso, self, filter);
85 85
86 if (nr < 0) { 86 if (nr < 0) {
87 pr_warning("Failed to open %s, continuing without symbols\n", 87 if (self->dso->has_build_id) {
88 self->dso->long_name); 88 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
89
90 build_id__sprintf(self->dso->build_id,
91 sizeof(self->dso->build_id),
92 sbuild_id);
93 pr_warning("%s with build id %s not found",
94 self->dso->long_name, sbuild_id);
95 } else
96 pr_warning("Failed to open %s",
97 self->dso->long_name);
98 pr_warning(", continuing without symbols\n");
89 return NULL; 99 return NULL;
90 } else if (nr == 0) { 100 } else if (nr == 0) {
91 const char *name = self->dso->long_name; 101 const char *name = self->dso->long_name;
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;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index e0d4a583f8dd..f8c1899af483 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -60,10 +60,12 @@ struct dso {
60 struct list_head node; 60 struct list_head node;
61 struct rb_root syms; 61 struct rb_root syms;
62 struct symbol *(*find_symbol)(struct dso *, u64 ip); 62 struct symbol *(*find_symbol)(struct dso *, u64 ip);
63 unsigned char adjust_symbols; 63 u8 adjust_symbols:1;
64 unsigned char slen_calculated; 64 u8 slen_calculated:1;
65 bool loaded; 65 u8 loaded:1;
66 u8 has_build_id:1;
66 unsigned char origin; 67 unsigned char origin;
68 u8 build_id[BUILD_ID_SIZE];
67 const char *short_name; 69 const char *short_name;
68 char *long_name; 70 char *long_name;
69 char name[0]; 71 char name[0];
@@ -81,8 +83,10 @@ void dsos__fprintf(FILE *fp);
81 83
82size_t dso__fprintf(struct dso *self, FILE *fp); 84size_t dso__fprintf(struct dso *self, FILE *fp);
83char dso__symtab_origin(const struct dso *self); 85char dso__symtab_origin(const struct dso *self);
86void dso__set_build_id(struct dso *self, void *build_id);
84 87
85int filename__read_build_id(const char *filename, void *bf, size_t size); 88int filename__read_build_id(const char *filename, void *bf, size_t size);
89int build_id__sprintf(u8 *self, int len, char *bf);
86 90
87int load_kernel(symbol_filter_t filter); 91int load_kernel(symbol_filter_t filter);
88 92