Commit 180ca71c authored by Thomas Richter's avatar Thomas Richter Committed by Arnaldo Carvalho de Melo

perf report: Support s390 diag event display on x86

Perf report fails to display s390 specific event numbered bd000
on an x86 platform. For example on s390 this works without error:

[root@m35lp76 perf]# uname -m
s390x
[root@m35lp76 perf]# ./perf record -e rbd000 -- find / >/dev/null
[ perf record: Woken up 3 times to write data ]
[ perf record: Captured and wrote 0.549 MB perf.data ]
[root@m35lp76 perf]# ./perf report -D --stdio  > /dev/null
[root@m35lp76 perf]#

Transfering this perf.data file to an x86 platform and executing
the same report command produces:

[root@f29 perf]# uname -m
x86_64
[root@f29 perf]# ./perf report -i ~/perf.data.m35lp76 --stdio
interpreting bpf_prog_info from systems with endianity is not yet supported
interpreting btf from systems with endianity is not yet supported
0x8c890 [0x8]: failed to process type: 68
Error:
failed to process sample

Event bd000 generates auxiliary data which is stored in big endian
format in the perf data file.
This error is caused by missing endianess handling on the x86 platform
when the data is displayed. Fix this by handling s390 auxiliary event
data depending on the local platform endianness.

Output after on x86:

[root@f29 perf]# ./perf report -D -i ~/perf.data.m35lp76 --stdio > /dev/null
interpreting bpf_prog_info from systems with endianity is not yet supported
interpreting btf from systems with endianity is not yet supported
[root@f29 perf]#

Committer notes:

Fix build breakage on older systems, such as CentOS:6 where using
nesting calls to the endian.h macros end up redefining local variables:

  util/s390-cpumsf.c: In function 's390_cpumsf_trailer_show':
  util/s390-cpumsf.c:333: error: declaration of '__v' shadows a previous local
  util/s390-cpumsf.c:333: error: shadowed declaration is here
  util/s390-cpumsf.c:333: error: declaration of '__x' shadows a previous local
  util/s390-cpumsf.c:333: error: shadowed declaration is here
  util/s390-cpumsf.c:334: error: declaration of '__v' shadows a previous local
  util/s390-cpumsf.c:334: error: shadowed declaration is here
  util/s390-cpumsf.c:334: error: declaration of '__x' shadows a previous local
  util/s390-cpumsf.c:334: error: shadowed declaration is here

  [perfbuilder@455a63ef60dc perf]$ gcc -v |& tail -1
  gcc version 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC)
  [perfbuilder@455a63ef60dc perf]$

Since there are several uses of

  be64toh(te->flags)

Introduce a variable to hold that and then use it, avoiding this case
that causes the above problems:

  -       local.bsdes = be16toh((be64toh(te->flags) >> 16 & 0xffff));
  +       local.bsdes = be16toh((flags >> 16 & 0xffff));

Its the same construct used in s390_cpumsf_diag_show() where we have a
'word' variable that is used just once, s390_cpumsf_basic_show() has
lots of uses and also uses a variable to hold the result of be16toh().

Some of those temp variables needed to be converted from 'unsigned long'
to 'unsigned long long' so as to build on 32-bit arches such as
debian:experimental-x-mipsel, the android NDK ones and
fedora:24-x-ARC-uClibc.
Signed-off-by: default avatarThomas Richter <tmricht@linux.ibm.com>
Reviewed-by: default avatarHendrik Brueckner <brueckner@linux.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Link: http://lkml.kernel.org/r/20190522064325.25596-1-tmricht@linux.ibm.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 8a07aa4e
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
* see Documentation/perf.data-file-format.txt. * see Documentation/perf.data-file-format.txt.
* PERF_RECORD_AUXTRACE_INFO: * PERF_RECORD_AUXTRACE_INFO:
* Defines a table of contains for PERF_RECORD_AUXTRACE records. This * Defines a table of contains for PERF_RECORD_AUXTRACE records. This
* record is generated during 'perf record' command. Each record contains up * record is generated during 'perf record' command. Each record contains
* to 256 entries describing offset and size of the AUXTRACE data in the * up to 256 entries describing offset and size of the AUXTRACE data in the
* perf.data file. * perf.data file.
* PERF_RECORD_AUXTRACE_ERROR: * PERF_RECORD_AUXTRACE_ERROR:
* Indicates an error during AUXTRACE collection such as buffer overflow. * Indicates an error during AUXTRACE collection such as buffer overflow.
...@@ -237,10 +237,33 @@ static int s390_cpumcf_dumpctr(struct s390_cpumsf *sf, ...@@ -237,10 +237,33 @@ static int s390_cpumcf_dumpctr(struct s390_cpumsf *sf,
return rc; return rc;
} }
/* Display s390 CPU measurement facility basic-sampling data entry */ /* Display s390 CPU measurement facility basic-sampling data entry
* Data written on s390 in big endian byte order and contains bit
* fields across byte boundaries.
*/
static bool s390_cpumsf_basic_show(const char *color, size_t pos, static bool s390_cpumsf_basic_show(const char *color, size_t pos,
struct hws_basic_entry *basic) struct hws_basic_entry *basicp)
{ {
struct hws_basic_entry *basic = basicp;
#if __BYTE_ORDER == __LITTLE_ENDIAN
struct hws_basic_entry local;
unsigned long long word = be64toh(*(unsigned long long *)basicp);
memset(&local, 0, sizeof(local));
local.def = be16toh(basicp->def);
local.prim_asn = word & 0xffff;
local.CL = word >> 30 & 0x3;
local.I = word >> 32 & 0x1;
local.AS = word >> 33 & 0x3;
local.P = word >> 35 & 0x1;
local.W = word >> 36 & 0x1;
local.T = word >> 37 & 0x1;
local.U = word >> 40 & 0xf;
local.ia = be64toh(basicp->ia);
local.gpp = be64toh(basicp->gpp);
local.hpp = be64toh(basicp->hpp);
basic = &local;
#endif
if (basic->def != 1) { if (basic->def != 1) {
pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos); pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos);
return false; return false;
...@@ -258,10 +281,22 @@ static bool s390_cpumsf_basic_show(const char *color, size_t pos, ...@@ -258,10 +281,22 @@ static bool s390_cpumsf_basic_show(const char *color, size_t pos,
return true; return true;
} }
/* Display s390 CPU measurement facility diagnostic-sampling data entry */ /* Display s390 CPU measurement facility diagnostic-sampling data entry.
* Data written on s390 in big endian byte order and contains bit
* fields across byte boundaries.
*/
static bool s390_cpumsf_diag_show(const char *color, size_t pos, static bool s390_cpumsf_diag_show(const char *color, size_t pos,
struct hws_diag_entry *diag) struct hws_diag_entry *diagp)
{ {
struct hws_diag_entry *diag = diagp;
#if __BYTE_ORDER == __LITTLE_ENDIAN
struct hws_diag_entry local;
unsigned long long word = be64toh(*(unsigned long long *)diagp);
local.def = be16toh(diagp->def);
local.I = word >> 32 & 0x1;
diag = &local;
#endif
if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) { if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) {
pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos); pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos);
return false; return false;
...@@ -272,35 +307,52 @@ static bool s390_cpumsf_diag_show(const char *color, size_t pos, ...@@ -272,35 +307,52 @@ static bool s390_cpumsf_diag_show(const char *color, size_t pos,
} }
/* Return TOD timestamp contained in an trailer entry */ /* Return TOD timestamp contained in an trailer entry */
static unsigned long long trailer_timestamp(struct hws_trailer_entry *te) static unsigned long long trailer_timestamp(struct hws_trailer_entry *te,
int idx)
{ {
/* te->t set: TOD in STCKE format, bytes 8-15 /* te->t set: TOD in STCKE format, bytes 8-15
* to->t not set: TOD in STCK format, bytes 0-7 * to->t not set: TOD in STCK format, bytes 0-7
*/ */
unsigned long long ts; unsigned long long ts;
memcpy(&ts, &te->timestamp[te->t], sizeof(ts)); memcpy(&ts, &te->timestamp[idx], sizeof(ts));
return ts; return be64toh(ts);
} }
/* Display s390 CPU measurement facility trailer entry */ /* Display s390 CPU measurement facility trailer entry */
static bool s390_cpumsf_trailer_show(const char *color, size_t pos, static bool s390_cpumsf_trailer_show(const char *color, size_t pos,
struct hws_trailer_entry *te) struct hws_trailer_entry *te)
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN
struct hws_trailer_entry local;
const unsigned long long flags = be64toh(te->flags);
memset(&local, 0, sizeof(local));
local.f = flags >> 63 & 0x1;
local.a = flags >> 62 & 0x1;
local.t = flags >> 61 & 0x1;
local.bsdes = be16toh((flags >> 16 & 0xffff));
local.dsdes = be16toh((flags & 0xffff));
memcpy(&local.timestamp, te->timestamp, sizeof(te->timestamp));
local.overflow = be64toh(te->overflow);
local.clock_base = be64toh(te->progusage[0]) >> 63 & 1;
local.progusage2 = be64toh(te->progusage2);
te = &local;
#endif
if (te->bsdes != sizeof(struct hws_basic_entry)) { if (te->bsdes != sizeof(struct hws_basic_entry)) {
pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos); pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos);
return false; return false;
} }
color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d" color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d"
" dsdes:%d Overflow:%lld Time:%#llx\n" " dsdes:%d Overflow:%lld Time:%#llx\n"
"\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n", "\t\tC:%d TOD:%#lx\n",
pos, pos,
te->f ? 'F' : ' ', te->f ? 'F' : ' ',
te->a ? 'A' : ' ', te->a ? 'A' : ' ',
te->t ? 'T' : ' ', te->t ? 'T' : ' ',
te->bsdes, te->dsdes, te->overflow, te->bsdes, te->dsdes, te->overflow,
trailer_timestamp(te), te->clock_base, te->progusage2, trailer_timestamp(te, te->clock_base),
te->progusage[0], te->progusage[1]); te->clock_base, te->progusage2);
return true; return true;
} }
...@@ -327,13 +379,13 @@ static bool s390_cpumsf_validate(int machine_type, ...@@ -327,13 +379,13 @@ static bool s390_cpumsf_validate(int machine_type,
*dsdes = *bsdes = 0; *dsdes = *bsdes = 0;
if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */ if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */
return false; return false;
if (basic->def != 1) /* No basic set entry, must be first */ if (be16toh(basic->def) != 1) /* No basic set entry, must be first */
return false; return false;
/* Check for trailer entry at end of SDB */ /* Check for trailer entry at end of SDB */
te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
- sizeof(*te)); - sizeof(*te));
*bsdes = te->bsdes; *bsdes = be16toh(te->bsdes);
*dsdes = te->dsdes; *dsdes = be16toh(te->dsdes);
if (!te->bsdes && !te->dsdes) { if (!te->bsdes && !te->dsdes) {
/* Very old hardware, use CPUID */ /* Very old hardware, use CPUID */
switch (machine_type) { switch (machine_type) {
...@@ -495,19 +547,27 @@ static bool s390_cpumsf_make_event(size_t pos, ...@@ -495,19 +547,27 @@ static bool s390_cpumsf_make_event(size_t pos,
static unsigned long long get_trailer_time(const unsigned char *buf) static unsigned long long get_trailer_time(const unsigned char *buf)
{ {
struct hws_trailer_entry *te; struct hws_trailer_entry *te;
unsigned long long aux_time; unsigned long long aux_time, progusage2;
bool clock_base;
te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
- sizeof(*te)); - sizeof(*te));
if (!te->clock_base) /* TOD_CLOCK_BASE value missing */ #if __BYTE_ORDER == __LITTLE_ENDIAN
clock_base = be64toh(te->progusage[0]) >> 63 & 0x1;
progusage2 = be64toh(te->progusage[1]);
#else
clock_base = te->clock_base;
progusage2 = te->progusage2;
#endif
if (!clock_base) /* TOD_CLOCK_BASE value missing */
return 0; return 0;
/* Correct calculation to convert time stamp in trailer entry to /* Correct calculation to convert time stamp in trailer entry to
* nano seconds (taken from arch/s390 function tod_to_ns()). * nano seconds (taken from arch/s390 function tod_to_ns()).
* TOD_CLOCK_BASE is stored in trailer entry member progusage2. * TOD_CLOCK_BASE is stored in trailer entry member progusage2.
*/ */
aux_time = trailer_timestamp(te) - te->progusage2; aux_time = trailer_timestamp(te, clock_base) - progusage2;
aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9); aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9);
return aux_time; return aux_time;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment