aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/session.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-01-14 09:23:10 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-16 04:58:45 -0500
commitba21594cddee0a3af582971656702b1c4509d8f5 (patch)
tree2526e75ba7479a5fd59f979962f1937c3104ad99 /tools/perf/util/session.c
parent0d755034dbd01e240eadf2d31f4f75d3088ccd21 (diff)
perf tools: Cross platform perf.data analysis support
There are still some problems related to loading vmlinux files, but those are unrelated to the feature implemented in this patch, so will get fixed in the next patches, but here are some results: 1. collect perf.data file on a Fedora 12 machine, x86_64, 64-bit userland 2. transfer it to a Debian Testing machine, PARISC64, 32-bit userland acme@parisc:~/git/linux-2.6-tip$ perf buildid-list | head -5 74f9930ee94475b6b3238caf3725a50d59cb994b [kernel.kallsyms] 55fdd56670453ea66c011158c4b9d30179c1d049 /lib/modules/2.6.33-rc4-tip+/kernel/net/ipv4/netfilter/ipt_MASQUERADE.ko 41adff63c730890480980d5d8ba513f1c216a858 /lib/modules/2.6.33-rc4-tip+/kernel/net/ipv4/netfilter/iptable_nat.ko 90a33def1077bb8e97b8a78546dc96c2de62df46 /lib/modules/2.6.33-rc4-tip+/kernel/net/ipv4/netfilter/nf_nat.ko 984c7bea90ce1376d5c8e7ef43a781801286e62d /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/tun.ko acme@parisc:~/git/linux-2.6-tip$ perf buildid-list | tail -5 22492f3753c6a67de5c7ccbd6b863390c92c0723 /usr/lib64/libXt.so.6.0.0 353802bb7e1b895ba43507cc678f951e778e4c6f /usr/lib64/libMagickCore.so.2.0.0 d10c2897558595efe7be8b0584cf7e6398bc776c /usr/lib64/libfprint.so.0.0.0 a83ecfb519a788774a84d5ddde633c9ba56c03ab /home/acme/bin/perf d3ca765a8ecf257d263801d7ad8c49c189082317 /usr/lib64/libdwarf.so.0.0 acme@parisc:~/git/linux-2.6-tip$ acme@parisc:~/git/linux-2.6-tip$ perf report --sort comm The file [kernel.kallsyms] cannot be used, trying to use /proc/kallsyms... ^^^^ The problem related to vmlinux handling, it shouldn't be trying this ^^^^ rather alien /proc/kallsyms at all... /lib64/libpthread-2.10.2.so with build id 5c68f7afeb33309c78037e374b0deee84dd441f6 not found, continuing without symbols /lib64/libc-2.10.2.so with build id eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 not found, continuing without symbols /home/acme/bin/perf with build id a83ecfb519a788774a84d5ddde633c9ba56c03ab not found, continuing without symbols /usr/sbin/openvpn with build id f2037a091ef36b591187a858d75e203690ea9409 not found, continuing without symbols Failed to open /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/e1000e/e1000e.ko, continuing without symbols Failed to open /lib/modules/2.6.33-rc4-tip+/kernel/drivers/net/wireless/iwlwifi/iwlcore.ko, continuing without symbols <SNIP more complaints about not finding the right build-ids, those will have to wait for 'perf archive' or plain copying what was collected by 'perf record' on the x86_64, source machine, see further below for an example of this > # Samples: 293085637 # # Overhead Command # ........ ............... # 61.70% find 23.50% perf 5.86% swapper 3.12% sshd 2.39% init 0.87% bash 0.86% sleep 0.59% dbus-daemon 0.25% hald 0.24% NetworkManager 0.19% hald-addon-rfki 0.15% openvpn 0.07% phy0 0.07% events/0 0.05% iwl3945 0.05% events/1 0.03% kondemand/0 acme@parisc:~/git/linux-2.6-tip$ Which matches what we get when running the same command for the same perf.data file on the F12, x86_64, source machine: [root@doppio linux-2.6-tip]# perf report --sort comm # Samples: 293085637 # # Overhead Command # ........ ............... # 61.70% find 23.50% perf 5.86% swapper 3.12% sshd 2.39% init 0.87% bash 0.86% sleep 0.59% dbus-daemon 0.25% hald 0.24% NetworkManager 0.19% hald-addon-rfki 0.15% openvpn 0.07% phy0 0.07% events/0 0.05% iwl3945 0.05% events/1 0.03% kondemand/0 [root@doppio linux-2.6-tip]# The other modes work as well, modulo the problem with vmlinux: acme@parisc:~/git/linux-2.6-tip$ perf report --sort comm,dso 2> /dev/null | head -15 # Samples: 293085637 # # Overhead Command Shared Object # ........ ............... ................................. # 35.11% find ffffffff81002b5a 18.25% perf ffffffff8102235f 16.17% find libc-2.10.2.so 9.07% find find 5.80% swapper ffffffff8102235f 3.95% perf libc-2.10.2.so 2.33% init ffffffff810091b9 1.65% sshd libcrypto.so.0.9.8k 1.35% find [e1000e] 0.68% sleep libc-2.10.2.so acme@parisc:~/git/linux-2.6-tip$ And the lack of the right buildids: acme@parisc:~/git/linux-2.6-tip$ perf report --sort comm,dso,symbol 2> /dev/null | head -15 # Samples: 293085637 # # Overhead Command Shared Object Symbol # ........ ............... ................................. ...... # 35.11% find ffffffff81002b5a [k] 0xffffffff81002b5a 18.25% perf ffffffff8102235f [k] 0xffffffff8102235f 16.17% find libc-2.10.2.so [.] 0x00000000045782 9.07% find find [.] 0x0000000000fb0e 5.80% swapper ffffffff8102235f [k] 0xffffffff8102235f 3.95% perf libc-2.10.2.so [.] 0x0000000007f398 2.33% init ffffffff810091b9 [k] 0xffffffff810091b9 1.65% sshd libcrypto.so.0.9.8k [.] 0x00000000105440 1.35% find [e1000e] [k] 0x00000000010948 0.68% sleep libc-2.10.2.so [.] 0x0000000011ad5b acme@parisc:~/git/linux-2.6-tip$ But if we: acme@parisc:~/git/linux-2.6-tip$ ls ~/.debug ls: cannot access /home/acme/.debug: No such file or directory acme@parisc:~/git/linux-2.6-tip$ mkdir -p ~/.debug/lib64/libc-2.10.2.so/ acme@parisc:~/git/linux-2.6-tip$ scp doppio:.debug/lib64/libc-2.10.2.so/* ~/.debug/lib64/libc-2.10.2.so/ acme@doppio's password: eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 100% 1783KB 714.7KB/s 00:02 acme@parisc:~/git/linux-2.6-tip$ mkdir -p ~/.debug/.build-id/eb acme@parisc:~/git/linux-2.6-tip$ ln -s ../../lib64/libc-2.10.2.so/eb4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 ~/.debug/.build-id/eb/4ec8fa8b2a5eb18cad173c92f27ed8887ed1c1 acme@parisc:~/git/linux-2.6-tip$ perf report --dsos libc-2.10.2.so 2> /dev/null # dso: libc-2.10.2.so # Samples: 64281170 # # Overhead Command Symbol # ........ ............... ...... # 14.98% perf [.] __GI_strcmp 12.30% find [.] __GI_memmove 9.25% find [.] _int_malloc 7.60% find [.] _IO_vfprintf_internal 6.10% find [.] _IO_new_file_xsputn 6.02% find [.] __GI_close 3.08% find [.] _IO_file_overflow_internal 3.08% find [.] malloc_consolidate 3.08% find [.] _int_free 3.08% find [.] __strchrnul 3.08% find [.] __getdents64 3.08% find [.] __write_nocancel 3.08% sleep [.] __GI__dl_addr 3.08% sshd [.] __libc_select 3.08% find [.] _IO_new_file_write 3.07% find [.] _IO_new_do_write 3.06% find [.] __GI___errno_location 3.05% find [.] __GI___libc_malloc 3.04% perf [.] __GI_memcpy 1.71% find [.] __fprintf_chk 1.29% bash [.] __gconv_transform_utf8_internal 0.79% dbus-daemon [.] __GI_strlen # # (For a higher level overview, try: perf report --sort comm,dso) # acme@parisc:~/git/linux-2.6-tip$ Which matches what we get on the source, F12, x86_64 machine: [root@doppio linux-2.6-tip]# perf report --dsos libc-2.10.2.so # dso: libc-2.10.2.so # Samples: 64281170 # # Overhead Command Symbol # ........ ............... ...... # 14.98% perf [.] __GI_strcmp 12.30% find [.] __GI_memmove 9.25% find [.] _int_malloc 7.60% find [.] _IO_vfprintf_internal 6.10% find [.] _IO_new_file_xsputn 6.02% find [.] __GI_close 3.08% find [.] _IO_file_overflow_internal 3.08% find [.] malloc_consolidate 3.08% find [.] _int_free 3.08% find [.] __strchrnul 3.08% find [.] __getdents64 3.08% find [.] __write_nocancel 3.08% sleep [.] __GI__dl_addr 3.08% sshd [.] __libc_select 3.08% find [.] _IO_new_file_write 3.07% find [.] _IO_new_do_write 3.06% find [.] __GI___errno_location 3.05% find [.] __GI___libc_malloc 3.04% perf [.] __GI_memcpy 1.71% find [.] __fprintf_chk 1.29% bash [.] __gconv_transform_utf8_internal 0.79% dbus-daemon [.] __GI_strlen # # (For a higher level overview, try: perf report --sort comm,dso) # [root@doppio linux-2.6-tip]# So I think this is really, really nice in that it demonstrates the portability of perf.data files and the use of build-ids accross such aliens worlds :-) There are some things to fix tho, like the bitmap on the header, but things are looking good. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1263478990-8200-2-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/session.c')
-rw-r--r--tools/perf/util/session.c108
1 files changed, 98 insertions, 10 deletions
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index e3ccdb46d6c4..604e14f6a6f9 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1,5 +1,6 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2 2
3#include <byteswap.h>
3#include <unistd.h> 4#include <unistd.h>
4#include <sys/types.h> 5#include <sys/types.h>
5 6
@@ -201,21 +202,88 @@ void event__print_totals(void)
201 event__name[i], event__total[i]); 202 event__name[i], event__total[i]);
202} 203}
203 204
205void mem_bswap_64(void *src, int byte_size)
206{
207 u64 *m = src;
208
209 while (byte_size > 0) {
210 *m = bswap_64(*m);
211 byte_size -= sizeof(u64);
212 ++m;
213 }
214}
215
216static void event__all64_swap(event_t *self)
217{
218 struct perf_event_header *hdr = &self->header;
219 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr));
220}
221
222static void event__comm_swap(event_t *self)
223{
224 self->comm.pid = bswap_32(self->comm.pid);
225 self->comm.tid = bswap_32(self->comm.tid);
226}
227
228static void event__mmap_swap(event_t *self)
229{
230 self->mmap.pid = bswap_32(self->mmap.pid);
231 self->mmap.tid = bswap_32(self->mmap.tid);
232 self->mmap.start = bswap_64(self->mmap.start);
233 self->mmap.len = bswap_64(self->mmap.len);
234 self->mmap.pgoff = bswap_64(self->mmap.pgoff);
235}
236
237static void event__task_swap(event_t *self)
238{
239 self->fork.pid = bswap_32(self->fork.pid);
240 self->fork.tid = bswap_32(self->fork.tid);
241 self->fork.ppid = bswap_32(self->fork.ppid);
242 self->fork.ptid = bswap_32(self->fork.ptid);
243 self->fork.time = bswap_64(self->fork.time);
244}
245
246static void event__read_swap(event_t *self)
247{
248 self->read.pid = bswap_32(self->read.pid);
249 self->read.tid = bswap_32(self->read.tid);
250 self->read.value = bswap_64(self->read.value);
251 self->read.time_enabled = bswap_64(self->read.time_enabled);
252 self->read.time_running = bswap_64(self->read.time_running);
253 self->read.id = bswap_64(self->read.id);
254}
255
256typedef void (*event__swap_op)(event_t *self);
257
258static event__swap_op event__swap_ops[] = {
259 [PERF_RECORD_MMAP] = event__mmap_swap,
260 [PERF_RECORD_COMM] = event__comm_swap,
261 [PERF_RECORD_FORK] = event__task_swap,
262 [PERF_RECORD_EXIT] = event__task_swap,
263 [PERF_RECORD_LOST] = event__all64_swap,
264 [PERF_RECORD_READ] = event__read_swap,
265 [PERF_RECORD_SAMPLE] = event__all64_swap,
266 [PERF_RECORD_MAX] = NULL,
267};
268
204static int perf_session__process_event(struct perf_session *self, 269static int perf_session__process_event(struct perf_session *self,
205 event_t *event, 270 event_t *event,
206 struct perf_event_ops *ops, 271 struct perf_event_ops *ops,
207 unsigned long offset, unsigned long head) 272 u64 offset, u64 head)
208{ 273{
209 trace_event(event); 274 trace_event(event);
210 275
211 if (event->header.type < PERF_RECORD_MAX) { 276 if (event->header.type < PERF_RECORD_MAX) {
212 dump_printf("%#lx [%#x]: PERF_RECORD_%s", 277 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
213 offset + head, event->header.size, 278 offset + head, event->header.size,
214 event__name[event->header.type]); 279 event__name[event->header.type]);
215 ++event__total[0]; 280 ++event__total[0];
216 ++event__total[event->header.type]; 281 ++event__total[event->header.type];
217 } 282 }
218 283
284 if (self->header.needs_swap && event__swap_ops[event->header.type])
285 event__swap_ops[event->header.type](event);
286
219 switch (event->header.type) { 287 switch (event->header.type) {
220 case PERF_RECORD_SAMPLE: 288 case PERF_RECORD_SAMPLE:
221 return ops->sample(event, self); 289 return ops->sample(event, self);
@@ -241,7 +309,15 @@ static int perf_session__process_event(struct perf_session *self,
241 } 309 }
242} 310}
243 311
244int perf_header__read_build_ids(int input, u64 offset, u64 size) 312void perf_event_header__bswap(struct perf_event_header *self)
313{
314 self->type = bswap_32(self->type);
315 self->misc = bswap_16(self->misc);
316 self->size = bswap_16(self->size);
317}
318
319int perf_header__read_build_ids(struct perf_header *self,
320 int input, u64 offset, u64 size)
245{ 321{
246 struct build_id_event bev; 322 struct build_id_event bev;
247 char filename[PATH_MAX]; 323 char filename[PATH_MAX];
@@ -256,6 +332,9 @@ int perf_header__read_build_ids(int input, u64 offset, u64 size)
256 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 332 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
257 goto out; 333 goto out;
258 334
335 if (self->needs_swap)
336 perf_event_header__bswap(&bev.header);
337
259 len = bev.header.size - sizeof(bev); 338 len = bev.header.size - sizeof(bev);
260 if (read(input, filename, len) != len) 339 if (read(input, filename, len) != len)
261 goto out; 340 goto out;
@@ -292,9 +371,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se
292int perf_session__process_events(struct perf_session *self, 371int perf_session__process_events(struct perf_session *self,
293 struct perf_event_ops *ops) 372 struct perf_event_ops *ops)
294{ 373{
295 int err; 374 int err, mmap_prot, mmap_flags;
296 unsigned long head, shift; 375 u64 head, shift;
297 unsigned long offset = 0; 376 u64 offset = 0;
298 size_t page_size; 377 size_t page_size;
299 event_t *event; 378 event_t *event;
300 uint32_t size; 379 uint32_t size;
@@ -330,9 +409,16 @@ out_getcwd_err:
330 offset += shift; 409 offset += shift;
331 head -= shift; 410 head -= shift;
332 411
412 mmap_prot = PROT_READ;
413 mmap_flags = MAP_SHARED;
414
415 if (self->header.needs_swap) {
416 mmap_prot |= PROT_WRITE;
417 mmap_flags = MAP_PRIVATE;
418 }
333remap: 419remap:
334 buf = mmap(NULL, page_size * self->mmap_window, PROT_READ, 420 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot,
335 MAP_SHARED, self->fd, offset); 421 mmap_flags, self->fd, offset);
336 if (buf == MAP_FAILED) { 422 if (buf == MAP_FAILED) {
337 pr_err("failed to mmap file\n"); 423 pr_err("failed to mmap file\n");
338 err = -errno; 424 err = -errno;
@@ -342,6 +428,8 @@ remap:
342more: 428more:
343 event = (event_t *)(buf + head); 429 event = (event_t *)(buf + head);
344 430
431 if (self->header.needs_swap)
432 perf_event_header__bswap(&event->header);
345 size = event->header.size; 433 size = event->header.size;
346 if (size == 0) 434 if (size == 0)
347 size = 8; 435 size = 8;
@@ -361,12 +449,12 @@ more:
361 449
362 size = event->header.size; 450 size = event->header.size;
363 451
364 dump_printf("\n%#lx [%#x]: event: %d\n", 452 dump_printf("\n%#Lx [%#x]: event: %d\n",
365 offset + head, event->header.size, event->header.type); 453 offset + head, event->header.size, event->header.type);
366 454
367 if (size == 0 || 455 if (size == 0 ||
368 perf_session__process_event(self, event, ops, offset, head) < 0) { 456 perf_session__process_event(self, event, ops, offset, head) < 0) {
369 dump_printf("%#lx [%#x]: skipping unknown header type: %d\n", 457 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n",
370 offset + head, event->header.size, 458 offset + head, event->header.size,
371 event->header.type); 459 event->header.type);
372 /* 460 /*