aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2011-09-06 11:12:26 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-09-23 13:37:27 -0400
commit936be50306a92356367f330ef9d44f1f62478d22 (patch)
tree5a69dbe1ee295fb7b09fd2605a37032d0a6b59b5 /tools/perf
parent6bb8f311a870d6042e0310309eb3d607ae52fe3e (diff)
perf tool: Fix endianness handling of u32 data in samples
Currently, analyzing PPC data files on x86 the cpu field is always 0 and the tid and pid are backwards. For example, analyzing a PPC file on PPC the pid/tid fields show: rsyslogd 1210/1212 and analyzing the same PPC file using an x86 perf binary shows: rsyslogd 1212/1210 The problem is that the swap_op method for samples is perf_event__all64_swap which assumes all elements in the sample_data struct are u64s. cpu, tid and pid are u32s and need to be handled individually. Given that the swap is done before the sample is parsed, the simplest solution is to undo the 64-bit swap of those elements when the sample is parsed and do the proper swap. The RAW data field is generic and perf cannot have programmatic knowledge of how to treat that data. Instead a warning is given to the user. Thanks to Anton Blanchard for providing a data file for a mult-CPU PPC system so I could verify the fix for the CPU fields. v3 -> v4: - fixed use of WARN_ONCE v2 -> v3: - used WARN_ONCE for message regarding raw data - removed struct wrapper around union - fixed whitespace issues v1 -> v2: - added a union for undoing the byte-swap on u64 and redoing swap on u32's to address compiler errors (see git commit 65014ab3) Cc: Anton Blanchard <anton@samba.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1315321946-16993-1-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-test.c2
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evsel.c54
-rw-r--r--tools/perf/util/session.h3
4 files changed, 47 insertions, 14 deletions
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 55f4c76f2821..efe696f936e2 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -561,7 +561,7 @@ static int test__basic_mmap(void)
561 } 561 }
562 562
563 err = perf_event__parse_sample(event, attr.sample_type, sample_size, 563 err = perf_event__parse_sample(event, attr.sample_type, sample_size,
564 false, &sample); 564 false, &sample, false);
565 if (err) { 565 if (err) {
566 pr_err("Can't parse sample, err = %d\n", err); 566 pr_err("Can't parse sample, err = %d\n", err);
567 goto out_munmap; 567 goto out_munmap;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 1d7f66488a88..357a85b85248 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id);
186 186
187int perf_event__parse_sample(const union perf_event *event, u64 type, 187int perf_event__parse_sample(const union perf_event *event, u64 type,
188 int sample_size, bool sample_id_all, 188 int sample_size, bool sample_id_all,
189 struct perf_sample *sample); 189 struct perf_sample *sample, bool swapped);
190 190
191#endif /* __PERF_RECORD_H */ 191#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index a03a36b7908a..c5748c52318f 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -7,6 +7,8 @@
7 * Released under the GPL v2. (and only v2, not any later version) 7 * Released under the GPL v2. (and only v2, not any later version)
8 */ 8 */
9 9
10#include <byteswap.h>
11#include "asm/bug.h"
10#include "evsel.h" 12#include "evsel.h"
11#include "evlist.h" 13#include "evlist.h"
12#include "util.h" 14#include "util.h"
@@ -342,10 +344,20 @@ static bool sample_overlap(const union perf_event *event,
342 344
343int perf_event__parse_sample(const union perf_event *event, u64 type, 345int perf_event__parse_sample(const union perf_event *event, u64 type,
344 int sample_size, bool sample_id_all, 346 int sample_size, bool sample_id_all,
345 struct perf_sample *data) 347 struct perf_sample *data, bool swapped)
346{ 348{
347 const u64 *array; 349 const u64 *array;
348 350
351 /*
352 * used for cross-endian analysis. See git commit 65014ab3
353 * for why this goofiness is needed.
354 */
355 union {
356 u64 val64;
357 u32 val32[2];
358 } u;
359
360
349 data->cpu = data->pid = data->tid = -1; 361 data->cpu = data->pid = data->tid = -1;
350 data->stream_id = data->id = data->time = -1ULL; 362 data->stream_id = data->id = data->time = -1ULL;
351 363
@@ -366,9 +378,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
366 } 378 }
367 379
368 if (type & PERF_SAMPLE_TID) { 380 if (type & PERF_SAMPLE_TID) {
369 u32 *p = (u32 *)array; 381 u.val64 = *array;
370 data->pid = p[0]; 382 if (swapped) {
371 data->tid = p[1]; 383 /* undo swap of u64, then swap on individual u32s */
384 u.val64 = bswap_64(u.val64);
385 u.val32[0] = bswap_32(u.val32[0]);
386 u.val32[1] = bswap_32(u.val32[1]);
387 }
388
389 data->pid = u.val32[0];
390 data->tid = u.val32[1];
372 array++; 391 array++;
373 } 392 }
374 393
@@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
395 } 414 }
396 415
397 if (type & PERF_SAMPLE_CPU) { 416 if (type & PERF_SAMPLE_CPU) {
398 u32 *p = (u32 *)array; 417
399 data->cpu = *p; 418 u.val64 = *array;
419 if (swapped) {
420 /* undo swap of u64, then swap on individual u32s */
421 u.val64 = bswap_64(u.val64);
422 u.val32[0] = bswap_32(u.val32[0]);
423 }
424
425 data->cpu = u.val32[0];
400 array++; 426 array++;
401 } 427 }
402 428
@@ -423,18 +449,24 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
423 } 449 }
424 450
425 if (type & PERF_SAMPLE_RAW) { 451 if (type & PERF_SAMPLE_RAW) {
426 u32 *p = (u32 *)array; 452 u.val64 = *array;
453 if (WARN_ONCE(swapped,
454 "Endianness of raw data not corrected!\n")) {
455 /* undo swap of u64, then swap on individual u32s */
456 u.val64 = bswap_64(u.val64);
457 u.val32[0] = bswap_32(u.val32[0]);
458 u.val32[1] = bswap_32(u.val32[1]);
459 }
427 460
428 if (sample_overlap(event, array, sizeof(u32))) 461 if (sample_overlap(event, array, sizeof(u32)))
429 return -EFAULT; 462 return -EFAULT;
430 463
431 data->raw_size = *p; 464 data->raw_size = u.val32[0];
432 p++;
433 465
434 if (sample_overlap(event, p, data->raw_size)) 466 if (sample_overlap(event, &u.val32[1], data->raw_size))
435 return -EFAULT; 467 return -EFAULT;
436 468
437 data->raw_data = p; 469 data->raw_data = &u.val32[1];
438 } 470 }
439 471
440 return 0; 472 return 0;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 170601e67d6b..974d0cbee5e9 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
162{ 162{
163 return perf_event__parse_sample(event, session->sample_type, 163 return perf_event__parse_sample(event, session->sample_type,
164 session->sample_size, 164 session->sample_size,
165 session->sample_id_all, sample); 165 session->sample_id_all, sample,
166 session->header.needs_swap);
166} 167}
167 168
168struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 169struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,