aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/header.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/header.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/header.c')
-rw-r--r--tools/perf/util/header.c63
1 files changed, 51 insertions, 12 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index ec96321eb9e4..b31e0ae4b8db 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1,8 +1,10 @@
1#include <sys/types.h> 1#include <sys/types.h>
2#include <byteswap.h>
2#include <unistd.h> 3#include <unistd.h>
3#include <stdio.h> 4#include <stdio.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <linux/list.h> 6#include <linux/list.h>
7#include <linux/kernel.h>
6 8
7#include "util.h" 9#include "util.h"
8#include "header.h" 10#include "header.h"
@@ -464,8 +466,21 @@ static int do_read(int fd, void *buf, size_t size)
464 return 0; 466 return 0;
465} 467}
466 468
469static int perf_header__getbuffer64(struct perf_header *self,
470 int fd, void *buf, size_t size)
471{
472 if (do_read(fd, buf, size))
473 return -1;
474
475 if (self->needs_swap)
476 mem_bswap_64(buf, size);
477
478 return 0;
479}
480
467int perf_header__process_sections(struct perf_header *self, int fd, 481int perf_header__process_sections(struct perf_header *self, int fd,
468 int (*process)(struct perf_file_section *self, 482 int (*process)(struct perf_file_section *self,
483 struct perf_header *ph,
469 int feat, int fd)) 484 int feat, int fd))
470{ 485{
471 struct perf_file_section *feat_sec; 486 struct perf_file_section *feat_sec;
@@ -486,7 +501,7 @@ int perf_header__process_sections(struct perf_header *self, int fd,
486 501
487 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 502 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
488 503
489 if (do_read(fd, feat_sec, sec_size)) 504 if (perf_header__getbuffer64(self, fd, feat_sec, sec_size))
490 goto out_free; 505 goto out_free;
491 506
492 err = 0; 507 err = 0;
@@ -494,7 +509,7 @@ int perf_header__process_sections(struct perf_header *self, int fd,
494 if (perf_header__has_feat(self, feat)) { 509 if (perf_header__has_feat(self, feat)) {
495 struct perf_file_section *sec = &feat_sec[idx++]; 510 struct perf_file_section *sec = &feat_sec[idx++];
496 511
497 err = process(sec, feat, fd); 512 err = process(sec, self, feat, fd);
498 if (err < 0) 513 if (err < 0)
499 break; 514 break;
500 } 515 }
@@ -511,10 +526,20 @@ int perf_file_header__read(struct perf_file_header *self,
511 lseek(fd, 0, SEEK_SET); 526 lseek(fd, 0, SEEK_SET);
512 527
513 if (do_read(fd, self, sizeof(*self)) || 528 if (do_read(fd, self, sizeof(*self)) ||
514 self->magic != PERF_MAGIC || 529 memcmp(&self->magic, __perf_magic, sizeof(self->magic)))
515 self->attr_size != sizeof(struct perf_file_attr))
516 return -1; 530 return -1;
517 531
532 if (self->attr_size != sizeof(struct perf_file_attr)) {
533 u64 attr_size = bswap_64(self->attr_size);
534
535 if (attr_size != sizeof(struct perf_file_attr))
536 return -1;
537
538 mem_bswap_64(self, offsetof(struct perf_file_header,
539 adds_features));
540 ph->needs_swap = true;
541 }
542
518 if (self->size != sizeof(*self)) { 543 if (self->size != sizeof(*self)) {
519 /* Support the previous format */ 544 /* Support the previous format */
520 if (self->size == offsetof(typeof(*self), adds_features)) 545 if (self->size == offsetof(typeof(*self), adds_features))
@@ -524,16 +549,28 @@ int perf_file_header__read(struct perf_file_header *self,
524 } 549 }
525 550
526 memcpy(&ph->adds_features, &self->adds_features, 551 memcpy(&ph->adds_features, &self->adds_features,
527 sizeof(self->adds_features)); 552 sizeof(ph->adds_features));
553 /*
554 * FIXME: hack that assumes that if we need swap the perf.data file
555 * may be coming from an arch with a different word-size, ergo different
556 * DEFINE_BITMAP format, investigate more later, but for now its mostly
557 * safe to assume that we have a build-id section. Trace files probably
558 * have several other issues in this realm anyway...
559 */
560 if (ph->needs_swap) {
561 memset(&ph->adds_features, 0, sizeof(ph->adds_features));
562 perf_header__set_feat(ph, HEADER_BUILD_ID);
563 }
528 564
529 ph->event_offset = self->event_types.offset; 565 ph->event_offset = self->event_types.offset;
530 ph->event_size = self->event_types.size; 566 ph->event_size = self->event_types.size;
531 ph->data_offset = self->data.offset; 567 ph->data_offset = self->data.offset;
532 ph->data_size = self->data.size; 568 ph->data_size = self->data.size;
533 return 0; 569 return 0;
534} 570}
535 571
536static int perf_file_section__process(struct perf_file_section *self, 572static int perf_file_section__process(struct perf_file_section *self,
573 struct perf_header *ph,
537 int feat, int fd) 574 int feat, int fd)
538{ 575{
539 if (lseek(fd, self->offset, SEEK_SET) < 0) { 576 if (lseek(fd, self->offset, SEEK_SET) < 0) {
@@ -548,7 +585,7 @@ static int perf_file_section__process(struct perf_file_section *self,
548 break; 585 break;
549 586
550 case HEADER_BUILD_ID: 587 case HEADER_BUILD_ID:
551 if (perf_header__read_build_ids(fd, self->offset, self->size)) 588 if (perf_header__read_build_ids(ph, fd, self->offset, self->size))
552 pr_debug("Failed to read buildids, continuing...\n"); 589 pr_debug("Failed to read buildids, continuing...\n");
553 break; 590 break;
554 default: 591 default:
@@ -560,7 +597,7 @@ static int perf_file_section__process(struct perf_file_section *self,
560 597
561int perf_header__read(struct perf_header *self, int fd) 598int perf_header__read(struct perf_header *self, int fd)
562{ 599{
563 struct perf_file_header f_header; 600 struct perf_file_header f_header;
564 struct perf_file_attr f_attr; 601 struct perf_file_attr f_attr;
565 u64 f_id; 602 u64 f_id;
566 int nr_attrs, nr_ids, i, j; 603 int nr_attrs, nr_ids, i, j;
@@ -577,8 +614,9 @@ int perf_header__read(struct perf_header *self, int fd)
577 struct perf_header_attr *attr; 614 struct perf_header_attr *attr;
578 off_t tmp; 615 off_t tmp;
579 616
580 if (do_read(fd, &f_attr, sizeof(f_attr))) 617 if (perf_header__getbuffer64(self, fd, &f_attr, sizeof(f_attr)))
581 goto out_errno; 618 goto out_errno;
619
582 tmp = lseek(fd, 0, SEEK_CUR); 620 tmp = lseek(fd, 0, SEEK_CUR);
583 621
584 attr = perf_header_attr__new(&f_attr.attr); 622 attr = perf_header_attr__new(&f_attr.attr);
@@ -589,7 +627,7 @@ int perf_header__read(struct perf_header *self, int fd)
589 lseek(fd, f_attr.ids.offset, SEEK_SET); 627 lseek(fd, f_attr.ids.offset, SEEK_SET);
590 628
591 for (j = 0; j < nr_ids; j++) { 629 for (j = 0; j < nr_ids; j++) {
592 if (do_read(fd, &f_id, sizeof(f_id))) 630 if (perf_header__getbuffer64(self, fd, &f_id, sizeof(f_id)))
593 goto out_errno; 631 goto out_errno;
594 632
595 if (perf_header_attr__add_id(attr, f_id) < 0) { 633 if (perf_header_attr__add_id(attr, f_id) < 0) {
@@ -610,7 +648,8 @@ int perf_header__read(struct perf_header *self, int fd)
610 events = malloc(f_header.event_types.size); 648 events = malloc(f_header.event_types.size);
611 if (events == NULL) 649 if (events == NULL)
612 return -ENOMEM; 650 return -ENOMEM;
613 if (do_read(fd, events, f_header.event_types.size)) 651 if (perf_header__getbuffer64(self, fd, events,
652 f_header.event_types.size))
614 goto out_errno; 653 goto out_errno;
615 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 654 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
616 } 655 }