aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/event.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-01-05 13:50:31 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-13 04:09:11 -0500
commit56b03f3c4d641dbdbce2e52a2969712e85b0e030 (patch)
tree3c15eb7ed163ca63bed395b233535f6fca2cccec /tools/perf/util/event.c
parentb9a63b9b56d6910a25e3d4905525aef150420a9b (diff)
perf tools: Handle relocatable kernels
DSOs don't have this problem because the kernel emits a PERF_MMAP for each new executable mapping it performs on monitored threads. To fix the kernel case we simulate the same behaviour, by having 'perf record' to synthesize a PERF_MMAP for the kernel, encoded like this: [root@doppio ~]# perf record -a -f sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.344 MB perf.data (~15038 samples) ] [root@doppio ~]# perf report -D | head -10 0xd0 [0x40]: event: 1 . . ... raw event: size 64 bytes . 0000: 01 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 ......@........ . 0010: 00 00 00 81 ff ff ff ff 00 00 00 00 00 00 00 00 ............... . 0020: 00 00 00 00 00 00 00 00 5b 6b 65 72 6e 65 6c 2e ........ [kernel . 0030: 6b 61 6c 6c 73 79 6d 73 2e 5f 74 65 78 74 5d 00 kallsyms._text] . 0xd0 [0x40]: PERF_RECORD_MMAP 0/0: [0xffffffff81000000((nil)) @ (nil)]: [kernel.kallsyms._text] I.e. we identify such event as having: .pid = 0 .filename = [kernel.kallsyms.REFNAME] .start = REFNAME addr in /proc/kallsyms at 'perf record' time and use now a hardcoded value of '.text' for REFNAME. Then, later, in 'perf report', if there are any kernel hits and thus we need to resolve kernel symbols, we search for REFNAME and if its address changed, relocation happened and we thus must change the kernel mapping routines to one that uses .pgoff as the relocation to apply. This way we use the same mechanism used for the other DSOs and don't have to do a two pass in all the kernel symbols. Reported-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> LKML-Reference: <1262717431-1246-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r--tools/perf/util/event.c64
1 files changed, 61 insertions, 3 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index bb0fd6da2d56..1a31feb9999f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -189,6 +189,50 @@ void event__synthesize_threads(int (*process)(event_t *event,
189 closedir(proc); 189 closedir(proc);
190} 190}
191 191
192struct process_symbol_args {
193 const char *name;
194 u64 start;
195};
196
197static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
198{
199 struct process_symbol_args *args = arg;
200
201 if (!symbol_type__is_a(type, MAP__FUNCTION) || strcmp(name, args->name))
202 return 0;
203
204 args->start = start;
205 return 1;
206}
207
208int event__synthesize_kernel_mmap(int (*process)(event_t *event,
209 struct perf_session *session),
210 struct perf_session *session,
211 const char *symbol_name)
212{
213 size_t size;
214 event_t ev = {
215 .header = { .type = PERF_RECORD_MMAP },
216 };
217 /*
218 * We should get this from /sys/kernel/sections/.text, but till that is
219 * available use this, and after it is use this as a fallback for older
220 * kernels.
221 */
222 struct process_symbol_args args = { .name = symbol_name, };
223
224 if (kallsyms__parse(&args, find_symbol_cb) <= 0)
225 return -ENOENT;
226
227 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
228 "[kernel.kallsyms.%s]", symbol_name) + 1;
229 size = ALIGN(size, sizeof(u64));
230 ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
231 ev.mmap.start = args.start;
232
233 return process(&ev, session);
234}
235
192static void thread__comm_adjust(struct thread *self) 236static void thread__comm_adjust(struct thread *self)
193{ 237{
194 char *comm = self->comm; 238 char *comm = self->comm;
@@ -240,9 +284,9 @@ int event__process_lost(event_t *self, struct perf_session *session)
240 284
241int event__process_mmap(event_t *self, struct perf_session *session) 285int event__process_mmap(event_t *self, struct perf_session *session)
242{ 286{
243 struct thread *thread = perf_session__findnew(session, self->mmap.pid); 287 struct thread *thread;
244 struct map *map = map__new(&self->mmap, MAP__FUNCTION, 288 struct map *map;
245 session->cwd, session->cwdlen); 289 static const char kmmap_prefix[] = "[kernel.kallsyms.";
246 290
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", 291 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
248 self->mmap.pid, self->mmap.tid, 292 self->mmap.pid, self->mmap.tid,
@@ -251,6 +295,20 @@ int event__process_mmap(event_t *self, struct perf_session *session)
251 (void *)(long)self->mmap.pgoff, 295 (void *)(long)self->mmap.pgoff,
252 self->mmap.filename); 296 self->mmap.filename);
253 297
298 if (self->mmap.pid == 0 &&
299 memcmp(self->mmap.filename, kmmap_prefix,
300 sizeof(kmmap_prefix) - 1) == 0) {
301 const char *symbol_name = (self->mmap.filename +
302 sizeof(kmmap_prefix) - 1);
303 perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
304 self->mmap.start);
305 return 0;
306 }
307
308 thread = perf_session__findnew(session, self->mmap.pid);
309 map = map__new(&self->mmap, MAP__FUNCTION,
310 session->cwd, session->cwdlen);
311
254 if (thread == NULL || map == NULL) 312 if (thread == NULL || map == NULL)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 313 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
256 else 314 else