Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Carry perf_event_attr bitfield throught different endians

When the perf data file is read cross architectures, the
perf_event__attr_swap function takes care about endianness of all the
struct fields except the bitfield flags.

The bitfield flags need to be transformed as well, since the bitfield
binary storage differs for both endians.

ABI says:
Bit-fields are allocated from right to left (least to most significant)
on little-endian implementations and from left to right (most to least
significant) on big-endian implementations.

The above seems to be byte specific, so we need to reverse each byte of
the bitfield. 'Internet' also says this might be implementation specific
and we probably need proper fix and carry perf_event_attr bitfield flags
in separate data file FEAT_ section. Thought this seems to work for now.

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/1337151548-2396-3-git-send-email-jolsa@redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Jiri Olsa and committed by
Arnaldo Carvalho de Melo
e108c66e 2e49a948

+34
+34
tools/perf/util/session.c
··· 481 481 event->read.id = bswap_64(event->read.id); 482 482 } 483 483 484 + static u8 revbyte(u8 b) 485 + { 486 + int rev = (b >> 4) | ((b & 0xf) << 4); 487 + rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2); 488 + rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1); 489 + return (u8) rev; 490 + } 491 + 492 + /* 493 + * XXX this is hack in attempt to carry flags bitfield 494 + * throught endian village. ABI says: 495 + * 496 + * Bit-fields are allocated from right to left (least to most significant) 497 + * on little-endian implementations and from left to right (most to least 498 + * significant) on big-endian implementations. 499 + * 500 + * The above seems to be byte specific, so we need to reverse each 501 + * byte of the bitfield. 'Internet' also says this might be implementation 502 + * specific and we probably need proper fix and carry perf_event_attr 503 + * bitfield flags in separate data file FEAT_ section. Thought this seems 504 + * to work for now. 505 + */ 506 + static void swap_bitfield(u8 *p, unsigned len) 507 + { 508 + unsigned i; 509 + 510 + for (i = 0; i < len; i++) { 511 + *p = revbyte(*p); 512 + p++; 513 + } 514 + } 515 + 484 516 /* exported for swapping attributes in file header */ 485 517 void perf_event__attr_swap(struct perf_event_attr *attr) 486 518 { ··· 526 494 attr->bp_type = bswap_32(attr->bp_type); 527 495 attr->bp_addr = bswap_64(attr->bp_addr); 528 496 attr->bp_len = bswap_64(attr->bp_len); 497 + 498 + swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); 529 499 } 530 500 531 501 static void perf_event__hdr_attr_swap(union perf_event *event)