perf session: Handle endianity swap on sample_id_all header data

Adding endianity swapping for event header attached via sample_id_all.

Currently we dont do that and it's causing wrong data to be read when
running report on architecture with different endianity than the record.

The perf is currently able to process 32-bit PPC samples on 32-bit
and 64-bit x86.

Together with other endianity patches, this change fixies perf report
discrepancies on origin and target systems as described in test 1
below, e.g. following perf report diff:

...
      0.12%               ps  [kernel.kallsyms]    [k] clear_page
-     0.12%              awk  bash                 [.] alloc_word_desc
+     0.12%              awk  bash                 [.] yyparse
      0.11%   beah-rhts-task  libpython2.6.so.1.0  [.] 0x5560e
      0.10%             perf  libc-2.12.so         [.] __ctype_toupper_loc
-     0.09%  rhts-test-runne  bash                 [.] maybe_make_export_env
+     0.09%  rhts-test-runne  bash                 [.] 0x385a0
      0.09%               ps  [kernel.kallsyms]    [k] page_fault
...

Note, running following to test perf endianity handling:
test 1)
  - origin system:
    # perf record -a -- sleep 10 (any perf record will do)
    # perf report > report.origin
    # perf archive perf.data

  - copy the perf.data, report.origin and perf.data.tar.bz2
    to a target system and run:
    # tar xjvf perf.data.tar.bz2 -C ~/.debug
    # perf report > report.target
    # diff -u report.origin report.target

  - the diff should produce no output
    (besides some white space stuff and possibly different
     date/TZ output)

test 2)
  - origin system:
    # perf record -ag -fo /tmp/perf.data -- sleep 1
  - mount origin system root to the target system on /mnt/origin
  - target system:
    # perf script --symfs /mnt/origin -I -i /mnt/origin/tmp/perf.data \
     --kallsyms /mnt/origin/proc/kallsyms
  - complete perf.data header is displayed

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
Tested-by: David Ahern <dsahern@gmail.com>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1338380624-7443-3-git-send-email-jolsa@redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Jiri Olsa 2012-05-30 14:23:43 +02:00 committed by Arnaldo Carvalho de Melo
parent 8db4841fc7
commit 268fb20f83

View File

@ -454,37 +454,65 @@ void mem_bswap_64(void *src, int byte_size)
} }
} }
static void perf_event__all64_swap(union perf_event *event) static void swap_sample_id_all(union perf_event *event, void *data)
{
void *end = (void *) event + event->header.size;
int size = end - data;
BUG_ON(size % sizeof(u64));
mem_bswap_64(data, size);
}
static void perf_event__all64_swap(union perf_event *event,
bool sample_id_all __used)
{ {
struct perf_event_header *hdr = &event->header; struct perf_event_header *hdr = &event->header;
mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
} }
static void perf_event__comm_swap(union perf_event *event) static void perf_event__comm_swap(union perf_event *event, bool sample_id_all)
{ {
event->comm.pid = bswap_32(event->comm.pid); event->comm.pid = bswap_32(event->comm.pid);
event->comm.tid = bswap_32(event->comm.tid); event->comm.tid = bswap_32(event->comm.tid);
if (sample_id_all) {
void *data = &event->comm.comm;
data += ALIGN(strlen(data) + 1, sizeof(u64));
swap_sample_id_all(event, data);
}
} }
static void perf_event__mmap_swap(union perf_event *event) static void perf_event__mmap_swap(union perf_event *event,
bool sample_id_all)
{ {
event->mmap.pid = bswap_32(event->mmap.pid); event->mmap.pid = bswap_32(event->mmap.pid);
event->mmap.tid = bswap_32(event->mmap.tid); event->mmap.tid = bswap_32(event->mmap.tid);
event->mmap.start = bswap_64(event->mmap.start); event->mmap.start = bswap_64(event->mmap.start);
event->mmap.len = bswap_64(event->mmap.len); event->mmap.len = bswap_64(event->mmap.len);
event->mmap.pgoff = bswap_64(event->mmap.pgoff); event->mmap.pgoff = bswap_64(event->mmap.pgoff);
if (sample_id_all) {
void *data = &event->mmap.filename;
data += ALIGN(strlen(data) + 1, sizeof(u64));
swap_sample_id_all(event, data);
}
} }
static void perf_event__task_swap(union perf_event *event) static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
{ {
event->fork.pid = bswap_32(event->fork.pid); event->fork.pid = bswap_32(event->fork.pid);
event->fork.tid = bswap_32(event->fork.tid); event->fork.tid = bswap_32(event->fork.tid);
event->fork.ppid = bswap_32(event->fork.ppid); event->fork.ppid = bswap_32(event->fork.ppid);
event->fork.ptid = bswap_32(event->fork.ptid); event->fork.ptid = bswap_32(event->fork.ptid);
event->fork.time = bswap_64(event->fork.time); event->fork.time = bswap_64(event->fork.time);
if (sample_id_all)
swap_sample_id_all(event, &event->fork + 1);
} }
static void perf_event__read_swap(union perf_event *event) static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
{ {
event->read.pid = bswap_32(event->read.pid); event->read.pid = bswap_32(event->read.pid);
event->read.tid = bswap_32(event->read.tid); event->read.tid = bswap_32(event->read.tid);
@ -492,6 +520,9 @@ static void perf_event__read_swap(union perf_event *event)
event->read.time_enabled = bswap_64(event->read.time_enabled); event->read.time_enabled = bswap_64(event->read.time_enabled);
event->read.time_running = bswap_64(event->read.time_running); event->read.time_running = bswap_64(event->read.time_running);
event->read.id = bswap_64(event->read.id); event->read.id = bswap_64(event->read.id);
if (sample_id_all)
swap_sample_id_all(event, &event->read + 1);
} }
static u8 revbyte(u8 b) static u8 revbyte(u8 b)
@ -543,7 +574,8 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
} }
static void perf_event__hdr_attr_swap(union perf_event *event) static void perf_event__hdr_attr_swap(union perf_event *event,
bool sample_id_all __used)
{ {
size_t size; size_t size;
@ -554,18 +586,21 @@ static void perf_event__hdr_attr_swap(union perf_event *event)
mem_bswap_64(event->attr.id, size); mem_bswap_64(event->attr.id, size);
} }
static void perf_event__event_type_swap(union perf_event *event) static void perf_event__event_type_swap(union perf_event *event,
bool sample_id_all __used)
{ {
event->event_type.event_type.event_id = event->event_type.event_type.event_id =
bswap_64(event->event_type.event_type.event_id); bswap_64(event->event_type.event_type.event_id);
} }
static void perf_event__tracing_data_swap(union perf_event *event) static void perf_event__tracing_data_swap(union perf_event *event,
bool sample_id_all __used)
{ {
event->tracing_data.size = bswap_32(event->tracing_data.size); event->tracing_data.size = bswap_32(event->tracing_data.size);
} }
typedef void (*perf_event__swap_op)(union perf_event *event); typedef void (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);
static perf_event__swap_op perf_event__swap_ops[] = { static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_MMAP] = perf_event__mmap_swap, [PERF_RECORD_MMAP] = perf_event__mmap_swap,
@ -999,6 +1034,15 @@ static int perf_session__process_user_event(struct perf_session *session, union
} }
} }
static void event_swap(union perf_event *event, bool sample_id_all)
{
perf_event__swap_op swap;
swap = perf_event__swap_ops[event->header.type];
if (swap)
swap(event, sample_id_all);
}
static int perf_session__process_event(struct perf_session *session, static int perf_session__process_event(struct perf_session *session,
union perf_event *event, union perf_event *event,
struct perf_tool *tool, struct perf_tool *tool,
@ -1007,9 +1051,8 @@ static int perf_session__process_event(struct perf_session *session,
struct perf_sample sample; struct perf_sample sample;
int ret; int ret;
if (session->header.needs_swap && if (session->header.needs_swap)
perf_event__swap_ops[event->header.type]) event_swap(event, session->sample_id_all);
perf_event__swap_ops[event->header.type](event);
if (event->header.type >= PERF_RECORD_HEADER_MAX) if (event->header.type >= PERF_RECORD_HEADER_MAX)
return -EINVAL; return -EINVAL;