Add support for S390 CPU-Measurement Sampling Facility auxiliary
trace data buffers.
Patch 1: Handle perf PERF_RECORD_AUXTRACE_INFO record for s390.
Perf report on s390 does not terminate with an error
message.
Patch 2: Display auxiliary trace data in raw (hex) format when
perf report interprets the perf.data input file with
option -D.
Patch 3: Display auxiliary trace in UI. Resolve addresses to
symbols and file names.
Thomas Richter (4):
perf auxtrace: Support for perf report -D for s390
perf report: Add raw report support for s390 auxiliary trace
perf report: Add GUI report support for s390 auxiliary trace
tools/perf/arch/s390/util/auxtrace.c | 1 +
tools/perf/util/Build | 1 +
tools/perf/util/auxtrace.c | 3 +
tools/perf/util/auxtrace.h | 1 +
tools/perf/util/s390-cpumsf-kernel.h | 71 ++
tools/perf/util/s390-cpumsf.c | 987 +++++++++++++++++++++++++++
tools/perf/util/s390-cpumsf.h | 21 +
7 files changed, 1085 insertions(+)
create mode 100644 tools/perf/util/s390-cpumsf-kernel.h
create mode 100644 tools/perf/util/s390-cpumsf.c
create mode 100644 tools/perf/util/s390-cpumsf.h
--
2.17.0
Add initial support for s390 auxiliary traces using the
CPU-Measurement Sampling Facility.
Support and ignore PERF_REPORT_AUXTRACE_INFO records
in the perf data file. Later patches will show the contents
of the auxiliary traces.
Setup the auxtrace queues and data structures for s390.
A raw dump of the perf.data file now does not show
an error when an auxtrace event is encountered.
Output before:
[root@s35lp76 perf]# ./perf report -D -i perf.data.auxtrace
0x128 [0x10]: failed to process type: 70
Error:
failed to process sample
0x128 [0x10]: event: 70
.
. ... raw event: size 16 bytes
. 0000: 00 00 00 46 00 00 00 10 00 00 00 00 00 00 00 00 ...F............
0x128 [0x10]: PERF_RECORD_AUXTRACE_INFO type: 0
[root@s35lp76 perf]#
Output after:
# ./perf report -D -i perf.data.auxtrace |fgrep PERF_RECORD_AUXTRACE
0 0 0x128 [0x10]: PERF_RECORD_AUXTRACE_INFO type: 5
0 0 0x25a66 [0x30]: PERF_RECORD_AUXTRACE size: 0x40000
offset: 0 ref: 0 idx: 4 tid: -1 cpu: 4
....
Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/arch/s390/util/auxtrace.c | 1 +
tools/perf/util/Build | 1 +
tools/perf/util/auxtrace.c | 3 +
tools/perf/util/auxtrace.h | 1 +
tools/perf/util/s390-cpumsf.c | 123 +++++++++++++++++++++++++++
tools/perf/util/s390-cpumsf.h | 21 +++++
6 files changed, 150 insertions(+)
create mode 100644 tools/perf/util/s390-cpumsf.c
create mode 100644 tools/perf/util/s390-cpumsf.h
diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c
index 3afe8256eff2..44c857388897 100644
--- a/tools/perf/arch/s390/util/auxtrace.c
+++ b/tools/perf/arch/s390/util/auxtrace.c
@@ -30,6 +30,7 @@ cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused,
struct auxtrace_info_event *auxtrace_info __maybe_unused,
size_t priv_size __maybe_unused)
{
+ auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF;
return 0;
}
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index b604ef334dc9..7efe15b9618d 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
libperf-$(CONFIG_AUXTRACE) += intel-bts.o
libperf-$(CONFIG_AUXTRACE) += arm-spe.o
libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
+libperf-$(CONFIG_AUXTRACE) += s390-cpumsf.o
ifdef CONFIG_LIBOPENCSD
libperf-$(CONFIG_AUXTRACE) += cs-etm.o
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index d056447520a2..ae8c37b219c9 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -56,6 +56,7 @@
#include "intel-pt.h"
#include "intel-bts.h"
#include "arm-spe.h"
+#include "s390-cpumsf.h"
#include "sane_ctype.h"
#include "symbol/kallsyms.h"
@@ -920,6 +921,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
return arm_spe_process_auxtrace_info(event, session);
case PERF_AUXTRACE_CS_ETM:
return cs_etm__process_auxtrace_info(event, session);
+ case PERF_AUXTRACE_S390_CPUMSF:
+ return s390_cpumsf_process_auxtrace_info(event, session);
case PERF_AUXTRACE_UNKNOWN:
default:
return -EINVAL;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index e731f55da072..71fc3bd74299 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -44,6 +44,7 @@ enum auxtrace_type {
PERF_AUXTRACE_INTEL_BTS,
PERF_AUXTRACE_CS_ETM,
PERF_AUXTRACE_ARM_SPE,
+ PERF_AUXTRACE_S390_CPUMSF,
};
enum itrace_period_type {
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
new file mode 100644
index 000000000000..e9a5ea21dbbf
--- /dev/null
+++ b/tools/perf/util/s390-cpumsf.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2018
+ * Auxtrace support for s390 CPU-Measurement Sampling Facility
+ *
+ * Author(s): Thomas Richter <[email protected]>
+ */
+
+#include <endian.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <inttypes.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+
+#include "cpumap.h"
+#include "color.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "machine.h"
+#include "session.h"
+#include "util.h"
+#include "thread.h"
+#include "debug.h"
+#include "auxtrace.h"
+#include "s390-cpumsf.h"
+
+struct s390_cpumsf {
+ struct auxtrace auxtrace;
+ struct auxtrace_queues queues;
+ struct auxtrace_heap heap;
+ struct perf_session *session;
+ struct machine *machine;
+ u32 auxtrace_type;
+ u32 pmu_type;
+};
+
+static int
+s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_sample *sample __maybe_unused,
+ struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+static int
+s390_cpumsf_process_auxtrace_event(struct perf_session *session __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+static int s390_cpumsf_flush(struct perf_session *session __maybe_unused,
+ struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+static void s390_cpumsf_free_events(struct perf_session *session)
+{
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+ struct auxtrace_queues *queues = &sf->queues;
+ unsigned int i;
+
+ for (i = 0; i < queues->nr_queues; i++)
+ zfree(&queues->queue_array[i].priv);
+ auxtrace_queues__free(queues);
+}
+
+static void s390_cpumsf_free(struct perf_session *session)
+{
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+
+ auxtrace_heap__free(&sf->heap);
+ s390_cpumsf_free_events(session);
+ session->auxtrace = NULL;
+ free(sf);
+}
+
+int s390_cpumsf_process_auxtrace_info(union perf_event *event,
+ struct perf_session *session)
+{
+ struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
+ struct s390_cpumsf *sf;
+ int err;
+
+ if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event))
+ return -EINVAL;
+
+ sf = zalloc(sizeof(struct s390_cpumsf));
+ if (sf == NULL)
+ return -ENOMEM;
+
+ err = auxtrace_queues__init(&sf->queues);
+ if (err)
+ goto err_free;
+
+ sf->session = session;
+ sf->machine = &session->machines.host; /* No kvm support */
+ sf->auxtrace_type = auxtrace_info->type;
+ sf->pmu_type = PERF_TYPE_RAW;
+
+ sf->auxtrace.process_event = s390_cpumsf_process_event;
+ sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event;
+ sf->auxtrace.flush_events = s390_cpumsf_flush;
+ sf->auxtrace.free_events = s390_cpumsf_free_events;
+ sf->auxtrace.free = s390_cpumsf_free;
+ session->auxtrace = &sf->auxtrace;
+
+ return 0;
+
+err_free:
+ free(sf);
+ return err;
+}
diff --git a/tools/perf/util/s390-cpumsf.h b/tools/perf/util/s390-cpumsf.h
new file mode 100644
index 000000000000..fb64d100555c
--- /dev/null
+++ b/tools/perf/util/s390-cpumsf.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright IBM Corp. 2018
+ * Auxtrace support for s390 CPU-Measurement Sampling Facility
+ *
+ * Author(s): Thomas Richter <[email protected]>
+ */
+
+#ifndef INCLUDE__PERF_S390_CPUMSF_H
+#define INCLUDE__PERF_S390_CPUMSF_H
+
+union perf_event;
+struct perf_session;
+struct perf_pmu;
+
+struct auxtrace_record *
+s390_cpumsf_recording_init(int *err, struct perf_pmu *s390_cpumsf_pmu);
+
+int s390_cpumsf_process_auxtrace_info(union perf_event *event,
+ struct perf_session *session);
+#endif
--
2.17.0
Add support for s390 auxiliary trace support.
Use 'perf record -e rbd000' to create the perf.data file.
The event also has the symbolic name SF_CYCLES_BASIC_DIAG,
using 'perf record -e SF_CYCLES_BASIC_DIAG' is equivalent.
Use 'perf report -D' to display the auxiliary trace data.
Output before:
0 0 0x25a66 [0x30]: PERF_RECORD_AUXTRACE size: 0x40000
offset: 0 ref: 0 idx: 4 tid: -1 cpu: 4
Nothing else
Output after:
0 0 0x25a66 [0x30]: PERF_RECORD_AUXTRACE size: 0x40000
offset: 0 ref: 0 idx: 4 tid: -1 cpu: 4
.
. ... s390 AUX data: size 262144 bytes
[00000000] Basic Def:0001 Inst:0000 TW AS:3 ASN:0xffff IA:0x0000000000c2f1bc
CL:1 HPP:0x8000000000000000 GPP:000000000000000000
[0x000020] Diag Def:8005
[0x0000bf] Basic Def:0001 Inst:0000 TW AS:3 ASN:0xffff IA:0x0000000000c2f1bc
CL:1 HPP:0x8000000000000000 GPP:000000000000000000
[0x0000df] Diag Def:8005
[0x00017e] Basic Def:0001 Inst:0000 TW AS:3 ASN:0xffff IA:0x0000000000c2f1bc
CL:1 HPP:0x8000000000000000 GPP:000000000000000000
....
[0x000fc0] Trailer F T bsdes:32 dsdes:159 Overflow:0 Time:0xd4ab59a8450fa108
C:1 TOD:0xd4ab4ec98ceb3832 1:0x8000000000000000 2:0xd4ab4ec98ceb3832
This output is shown for every sampled data block. The
output contains the
- basic-sampling data entry
- diagnostic-sampling data entry
- trailer entry
The basic sampling entry and diagnostic sampling entry sizes
can be extracted using the trailer entries in the SDB.
On older hardware these values (bsdes and dsdes in the
trailer entry) are reserved and zero. Older hardware use hard
coded values based on the s390 machine type.
Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/util/s390-cpumsf-kernel.h | 71 ++++++++
tools/perf/util/s390-cpumsf.c | 244 ++++++++++++++++++++++++++-
2 files changed, 314 insertions(+), 1 deletion(-)
create mode 100644 tools/perf/util/s390-cpumsf-kernel.h
diff --git a/tools/perf/util/s390-cpumsf-kernel.h b/tools/perf/util/s390-cpumsf-kernel.h
new file mode 100644
index 000000000000..f1dc8eb08607
--- /dev/null
+++ b/tools/perf/util/s390-cpumsf-kernel.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Auxtrace support for s390 CPU measurement sampling facility
+ *
+ * Copyright IBM Corp. 2018
+ * Author(s): Hendrik Brueckner <[email protected]>
+ * Thomas Richter <[email protected]>
+ */
+#ifndef S390_CPUMSF_KERNEL_H
+#define S390_CPUMSF_KERNEL_H
+
+#define S390_CPUMSF_PAGESZ 4096 /* Size of sample block units */
+#define S390_CPUMSF_DIAG_DEF_FIRST 0x8001 /* Diagnostic entry lowest id */
+
+struct hws_basic_entry {
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int R:4; /* 16-19 reserved */
+ unsigned int U:4; /* 20-23 Number of unique instruct. */
+ unsigned int z:2; /* zeros */
+ unsigned int T:1; /* 26 PSW DAT mode */
+ unsigned int W:1; /* 27 PSW wait state */
+ unsigned int P:1; /* 28 PSW Problem state */
+ unsigned int AS:2; /* 29-30 PSW address-space control */
+ unsigned int I:1; /* 31 entry valid or invalid */
+ unsigned int CL:2; /* 32-33 Configuration Level */
+ unsigned int:14;
+ unsigned int prim_asn:16; /* primary ASN */
+ unsigned long long ia; /* Instruction Address */
+ unsigned long long gpp; /* Guest Program Parameter */
+ unsigned long long hpp; /* Host Program Parameter */
+} __packed;
+
+struct hws_diag_entry {
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int R:15; /* 16-19 and 20-30 reserved */
+ unsigned int I:1; /* 31 entry valid or invalid */
+ u8 data[]; /* Machine-dependent sample data */
+} __packed;
+
+struct hws_combined_entry {
+ struct hws_basic_entry basic; /* Basic-sampling data entry */
+ struct hws_diag_entry diag; /* Diagnostic-sampling data entry */
+};
+
+struct hws_trailer_entry {
+ union {
+ struct {
+ unsigned int f:1; /* 0 - Block Full Indicator */
+ unsigned int a:1; /* 1 - Alert request control */
+ unsigned int t:1; /* 2 - Timestamp format */
+ unsigned int:29; /* 3 - 31: Reserved */
+ unsigned int bsdes:16; /* 32-47: size of basic SDE */
+ unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
+ };
+ unsigned long long flags; /* 0 - 64: All indicators */
+ };
+ unsigned long long overflow; /* 64 - sample Overflow count */
+ unsigned char timestamp[16]; /* 16 - 31 timestamp */
+ unsigned long long reserved1; /* 32 -Reserved */
+ unsigned long long reserved2; /* */
+ union { /* 48 - reserved for programming use */
+ struct {
+ unsigned long long clock_base:1; /* in progusage2 */
+ unsigned long long progusage1:63;
+ unsigned long long progusage2;
+ };
+ unsigned long long progusage[2];
+ };
+};
+
+#endif
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index e9a5ea21dbbf..831b9623c778 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -26,6 +26,7 @@
#include "debug.h"
#include "auxtrace.h"
#include "s390-cpumsf.h"
+#include "s390-cpumsf-kernel.h"
struct s390_cpumsf {
struct auxtrace auxtrace;
@@ -35,8 +36,210 @@ struct s390_cpumsf {
struct machine *machine;
u32 auxtrace_type;
u32 pmu_type;
+ u16 machine_type;
};
+/* Display s390 CPU measurement facility basic-sampling data entry */
+static bool s390_cpumsf_basic_show(const char *color, size_t pos,
+ struct hws_basic_entry *basic)
+{
+ if (basic->def != 1) {
+ pr_err("Invalid AUX trace basic entry [%#08lx]\n", pos);
+ return false;
+ }
+ color_fprintf(stdout, color, " [%#08x] Basic Def:%04x Inst:%#04x"
+ " %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n"
+ "\t\tCL:%d HPP:%#018llx GPP:%#018llx\n",
+ pos, basic->def, basic->U,
+ basic->T ? 'T' : ' ',
+ basic->W ? 'W' : ' ',
+ basic->P ? 'P' : ' ',
+ basic->I ? 'I' : ' ',
+ basic->AS, basic->prim_asn, basic->ia, basic->CL,
+ basic->hpp, basic->gpp);
+ return true;
+}
+
+/* Display s390 CPU measurement facility diagnostic-sampling data entry */
+static bool s390_cpumsf_diag_show(const char *color, size_t pos,
+ struct hws_diag_entry *diag)
+{
+ if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) {
+ pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
+ return false;
+ }
+ color_fprintf(stdout, color, " [%#08x] Diag Def:%04x %c\n",
+ pos, diag->def, diag->I ? 'I' : ' ');
+ return true;
+}
+
+/* Return TOD timestamp contained in an trailer entry */
+static unsigned long long trailer_timestamp(struct hws_trailer_entry *te)
+{
+ /* te->t set: TOD in STCKE format, bytes 8-15
+ * to->t not set: TOD in STCK format, bytes 0-7
+ */
+ return *((unsigned long long *) &te->timestamp[te->t]);
+}
+
+/* Display s390 CPU measurement facility trailer entry */
+static bool s390_cpumsf_trailer_show(const char *color, size_t pos,
+ struct hws_trailer_entry *te)
+{
+ if (te->bsdes != sizeof(struct hws_basic_entry)) {
+ pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
+ return false;
+ }
+ color_fprintf(stdout, color, " [%#08x] Trailer %c%c%c bsdes:%d"
+ " dsdes:%d Overflow:%lld Time:%#llx\n"
+ "\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n",
+ pos,
+ te->f ? 'F' : ' ',
+ te->a ? 'A' : ' ',
+ te->t ? 'T' : ' ',
+ te->bsdes, te->dsdes, te->overflow,
+ trailer_timestamp(te), te->clock_base, te->progusage2,
+ te->progusage[0], te->progusage[1]);
+ return true;
+}
+
+/* Test a sample data block. It must be 4KB or a multiple thereof in size and
+ * 4KB page aligned. Each sample data page has a trailer entry at the
+ * end which contains the sample entry data sizes.
+ *
+ * Return true if the sample data block passes the checks and set the
+ * basic set entry size and diagnostic set entry size.
+ *
+ * Return false on failure.
+ *
+ * Note: Old hardware does not set the basic or diagnostic entry sizes
+ * in the trailer entry. Use the type number instead.
+ */
+static bool s390_cpumsf_validate(int machine_type,
+ unsigned char *buf, size_t len,
+ unsigned short *bsdes,
+ unsigned short *dsdes)
+{
+ struct hws_basic_entry *basic = (struct hws_basic_entry *)buf;
+ struct hws_trailer_entry *te;
+
+ *dsdes = *bsdes = 0;
+ if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */
+ return false;
+ if (basic->def != 1) /* No basic set entry, must be first */
+ return false;
+ /* Check for trailer entry at end of SDB */
+ te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
+ - sizeof(*te));
+ *bsdes = te->bsdes;
+ *dsdes = te->dsdes;
+ if (!te->bsdes && !te->dsdes) {
+ /* Very old hardware, use CPUID */
+ switch (machine_type) {
+ case 2097:
+ case 2098:
+ *dsdes = 64;
+ *bsdes = 32;
+ break;
+ case 2817:
+ case 2818:
+ *dsdes = 74;
+ *bsdes = 32;
+ break;
+ case 2827:
+ case 2828:
+ *dsdes = 85;
+ *bsdes = 32;
+ break;
+ default:
+ /* Illegal trailer entry */
+ return false;
+ }
+ }
+ return true;
+}
+
+/* Return true if there is room for another entry */
+static bool s390_cpumsf_reached_trailer(size_t entry_sz, size_t pos)
+{
+ size_t payload = S390_CPUMSF_PAGESZ - sizeof(struct hws_trailer_entry);
+
+ if (payload - (pos & (S390_CPUMSF_PAGESZ - 1)) < entry_sz)
+ return false;
+ return true;
+}
+
+/* Dump an auxiliary buffer. These buffers are multiple of
+ * 4KB SDB pages.
+ */
+static void s390_cpumsf_dump(struct s390_cpumsf *sf,
+ unsigned char *buf, size_t len)
+{
+ const char *color = PERF_COLOR_BLUE;
+ struct hws_basic_entry *basic;
+ struct hws_diag_entry *diag;
+ size_t pos = 0;
+ unsigned short bsdes, dsdes;
+
+ color_fprintf(stdout, color,
+ ". ... s390 AUX data: size %zu bytes\n",
+ len);
+
+ if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
+ &dsdes)) {
+ pr_err("Invalid AUX trace data block size:%zu"
+ " (type:%d bsdes:%hd dsdes:%hd)\n",
+ len, sf->machine_type, bsdes, dsdes);
+ return;
+ }
+
+ /* s390 kernel always returns 4KB blocks fully occupied,
+ * no partially filled SDBs.
+ */
+ while (pos < len) {
+ /* Handle Basic entry */
+ basic = (struct hws_basic_entry *)(buf + pos);
+ if (s390_cpumsf_basic_show(color, pos, basic))
+ pos += bsdes;
+ else
+ return;
+
+ /* Handle Diagnostic entry */
+ diag = (struct hws_diag_entry *)(buf + pos);
+ if (s390_cpumsf_diag_show(color, pos, diag))
+ pos += dsdes;
+ else
+ return;
+
+ /* Check for trailer entry */
+ if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
+ /* Show trailer entry */
+ struct hws_trailer_entry te;
+
+ pos = (pos + S390_CPUMSF_PAGESZ)
+ & ~(S390_CPUMSF_PAGESZ - 1);
+ pos -= sizeof(te);
+ memcpy(&te, buf + pos, sizeof(te));
+ /* Set descriptor sizes in case of old hardware
+ * where these values are not set.
+ */
+ te.bsdes = bsdes;
+ te.dsdes = dsdes;
+ if (s390_cpumsf_trailer_show(color, pos, &te))
+ pos += sizeof(te);
+ else
+ return;
+ }
+ }
+}
+
+static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf,
+ size_t len)
+{
+ printf(".\n");
+ s390_cpumsf_dump(sf, buf, len);
+}
+
static int
s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
union perf_event *event __maybe_unused,
@@ -47,10 +250,40 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
}
static int
-s390_cpumsf_process_auxtrace_event(struct perf_session *session __maybe_unused,
+s390_cpumsf_process_auxtrace_event(struct perf_session *session,
union perf_event *event __maybe_unused,
struct perf_tool *tool __maybe_unused)
{
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+
+ int fd = perf_data__fd(session->data);
+ struct auxtrace_buffer *buffer;
+ off_t data_offset;
+ int err;
+
+ if (perf_data__is_pipe(session->data)) {
+ data_offset = 0;
+ } else {
+ data_offset = lseek(fd, 0, SEEK_CUR);
+ if (data_offset == -1)
+ return -errno;
+ }
+
+ err = auxtrace_queues__add_event(&sf->queues, session, event,
+ data_offset, &buffer);
+ if (err)
+ return err;
+
+ /* Dump here after copying piped trace out of the pipe */
+ if (dump_trace) {
+ if (auxtrace_buffer__get_data(buffer, fd)) {
+ s390_cpumsf_dump_event(sf, buffer->data,
+ buffer->size);
+ auxtrace_buffer__put_data(buffer);
+ }
+ }
return 0;
}
@@ -85,6 +318,14 @@ static void s390_cpumsf_free(struct perf_session *session)
free(sf);
}
+static int s390_cpumsf_get_type(const char *cpuid)
+{
+ int ret, family = 0;
+
+ ret = sscanf(cpuid, "%*[^,],%u", &family);
+ return (ret == 1) ? family : 0;
+}
+
int s390_cpumsf_process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
@@ -107,6 +348,7 @@ int s390_cpumsf_process_auxtrace_info(union perf_event *event,
sf->machine = &session->machines.host; /* No kvm support */
sf->auxtrace_type = auxtrace_info->type;
sf->pmu_type = PERF_TYPE_RAW;
+ sf->machine_type = s390_cpumsf_get_type(session->evlist->env->cpuid);
sf->auxtrace.process_event = s390_cpumsf_process_event;
sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event;
--
2.17.0
Add support for s390 auxiliary trace support.
Use 'perf record -e rbd000 -- ls' to create the perf.data file.
Use 'perf report' to display the auxiliary trace data.
Output before:
[root@s35lp76 perf]# ./perf report --stdio
0x128 [0x10]: failed to process type: 70
Error:
failed to process sample
[root@s35lp76 perf]#
Output after:
[root@s35lp76 perf]# ./perf report --stdio
18.21% 18.21% ls [kernel.kallsyms] [k] ftrace_likely_update
9.52% 9.52% ls [kernel.kallsyms] [k] lock_acquire
9.38% 9.38% ls [kernel.kallsyms] [k] lock_release
3.45% 3.45% ls [kernel.kallsyms] [k] lock_acquired
2.88% 2.88% ls [kernel.kallsyms] [k] link_path_walk
2.63% 2.63% ls [kernel.kallsyms] [k] __d_lookup
2.38% 2.38% ls [kernel.kallsyms] [k] __d_lookup_rcu
2.04% 2.04% ls [kernel.kallsyms] [k] ___might_sleep
1.83% 1.83% ls [kernel.kallsyms] [k] debug_lockdep_rcu_enabled
1.44% 1.44% ls [kernel.kallsyms] [k] dput
....
Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/util/s390-cpumsf.c | 593 +++++++++++++++++++++++++++++++++-
1 file changed, 585 insertions(+), 8 deletions(-)
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index 831b9623c778..32b165250338 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -4,6 +4,138 @@
* Auxtrace support for s390 CPU-Measurement Sampling Facility
*
* Author(s): Thomas Richter <[email protected]>
+ *
+ * Auxiliary traces are collected during perf record using rbd000 event.
+ * Several PERF_RECORD_XXX are generated during recording:
+ *
+ * PERF_RECORD_AUX:
+ * Records that new data landed in the AUX buffer part.
+ * PERF_RECORD_AUXTRACE:
+ * Defines auxtrace data. Followed by the actual data. The contents of
+ * the auxtrace data is dependent on the event and the CPU.
+ * This record is generated by perf record command. For details
+ * see Documentation/perf.data-file-format.txt.
+ * PERF_RECORD_AUXTRACE_INFO:
+ * Defines a table of contains for PERF_RECORD_AUXTRACE records. This
+ * recordis generated during perf record command. Each record contains up
+ * to 256 entries describing offset and size of the AUXTRACE data in the
+ * perf.data file.
+ * PERF_RECORD_AUXTRACE_ERROR:
+ * Indicates an error during AUXTRACE collection such as buffer overflow.
+ * PERF_RECORD_FINISHED_ROUND:
+ * Perf events are not necessarily in time stamp order, as they can be
+ * collected in parallel on different CPUs. If the events should be
+ * processed in time order they need to be sorted first.
+ * Perf report guarantees that there is no reordering over a
+ * PERF_RECORD_FINISHED_ROUND boundary event. All perf records with a
+ * time stamp lower than this record are processed (and displayed) before
+ * the succeeding perf record are processed.
+ *
+ * These records are evaluated during perf report command.
+ *
+ * 1. PERF_RECORD_AUXTRACE_INFO is used to set up the infrastructure for
+ * auxiliary trace data processing. See s390_cpumsf_process_auxtrace_info()
+ * below.
+ * Auxiliary trace data is collected per CPU. To merge the data into the report
+ * an auxtrace_queue is created for each CPU. It is assumed that the auxtrace
+ * data is in ascending order.
+ *
+ * Each queue has a double linked list of auxtrace_buffers. This list contains
+ * the offset and size of a CPU's auxtrace data. During auxtrace processing
+ * the data portion is mmap()'ed.
+ *
+ * To sort the queues in chronological order, all queue access is controlled
+ * by the auxtrace_heap. This is basicly a stack, each stack element has two
+ * entries, the queue number and a time stamp. However the stack is sorted by
+ * the time stamps. The highest time stamp is at the bottom the lowest
+ * (nearest) time stamp is at the top. That sort order is maintained at all
+ * times!
+ *
+ * After the auxtrace infrastructure has been setup, the auxtrace queues are
+ * filled with data (offset/size pairs) and the auxtrace_heap is populated.
+ *
+ * 2. PERF_RECORD_XXX processing triggers access to the auxtrace_queues.
+ * Each record is handled by s390_cpumsf_process_event(). The time stamp of
+ * the perf record is compared with the time stamp located on the auxtrace_heap
+ * top element. If that time stamp is lower than the time stamp from the
+ * record sample, the auxtrace queues will be processed. As auxtrace queues
+ * control many auxtrace_buffers and each buffer can be quite large, the
+ * auxtrace buffer might be processed only partially. In this case the
+ * position in the auxtrace_buffer of that queue is remembered and the time
+ * stamp of the last processed entry of the auxtrace_buffer replaces the
+ * current auxtrace_heap top.
+ *
+ * 3. Auxtrace_queues might run of out data and are feeded by the
+ * PERF_RECORD_AUXTRACE handling, see s390_cpumsf_process_auxtrace_event().
+ *
+ * Event Generation
+ * Each sampling-data entry in the auxilary trace data generates a perf sample.
+ * This sample is filled
+ * with data from the auxtrace such as PID/TID, instruction address, CPU state,
+ * etc. This sample is processed with perf_session__deliver_synth_event() to
+ * be included into the GUI.
+ *
+ * 4. PERF_RECORD_FINISHED_ROUND event is used to process all the remaining
+ * auxiliary traces entries until the time stamp of this record is reached
+ * auxtrace_heap top. This is triggered by ordered_event->deliver().
+ *
+ *
+ * Perf event processing.
+ * Event processing of PERF_RECORD_XXX entries relies on time stamp entries.
+ * This is the function call sequence:
+ *
+ * __cmd_report()
+ * |
+ * perf_session__process_events()
+ * |
+ * __perf_session__process_events()
+ * |
+ * perf_session__process_event()
+ * | This functions splits the PERF_RECORD_XXX records.
+ * | - Those generated by perf record command (type number equal or higher
+ * | than PERF_RECORD_USER_TYPE_START) are handled by
+ * | perf_session__process_user_event(see below)
+ * | - Those generated by the kernel are handled by
+ * | perf_evlist__parse_sample_timestamp()
+ * |
+ * perf_evlist__parse_sample_timestamp()
+ * | Extract time stamp from sample data.
+ * |
+ * perf_session__queue_event()
+ * | If timestamp is positive the sample is entered into an ordered_event
+ * | list, sort order is the timestamp. The event processing is deferred until
+ * | later (see perf_session__process_user_event()).
+ * | Other timestamps (0 or -1) are handled immediately by
+ * | perf_session__deliver_event(). These are events generated at start up
+ * | of command perf record. They create PERF_RECORD_COMM and PERF_RECORD_MMAP*
+ * | records. They are needed to create a list of running processes and its
+ * | memory mappings and layout. They are needed at the beginning to enable
+ * | command perf report to create process trees and memory mappings.
+ * |
+ * perf_session__deliver_event()
+ * | Delivers a PERF_RECORD_XXX entry for handling.
+ * |
+ * auxtrace__process_event()
+ * | The timestamp of the PERF_RECORD_XXX entry is taken to correlate with
+ * | time stamps from the auxiliary trace buffers. This enables
+ * | synchronization between auxiliary trace data and the events on the
+ * | perf.data file.
+ * |
+ * machine__deliver_event()
+ * | Handles the PERF_RECORD_XXX event. This depends on the record type.
+ * It might update the process tree, update a process memory map or enter
+ * a sample with IP and call back chain data into GUI data pool.
+ *
+ *
+ * Deferred processing determined by perf_session__process_user_event() is
+ * finally processed when a PERF_RECORD_FINISHED_ROUND is encountered. These
+ * are generated during command perf record.
+ * The timestamp of PERF_RECORD_FINISHED_ROUND event is taken to process all
+ * PERF_RECORD_XXX entries stored in the ordered_event list. This list was
+ * built up while reading the perf.data file.
+ * Each event is now processed by calling perf_session__deliver_event().
+ * This enables time synchronization between the data in the perf.data file and
+ * the data in the auxiliary trace buffers.
*/
#include <endian.h>
@@ -37,6 +169,14 @@ struct s390_cpumsf {
u32 auxtrace_type;
u32 pmu_type;
u16 machine_type;
+ bool data_queued;
+};
+
+struct s390_cpumsf_queue {
+ struct s390_cpumsf *sf;
+ unsigned int queue_nr;
+ struct auxtrace_buffer *buffer;
+ int cpu;
};
/* Display s390 CPU measurement facility basic-sampling data entry */
@@ -178,8 +318,8 @@ static void s390_cpumsf_dump(struct s390_cpumsf *sf,
const char *color = PERF_COLOR_BLUE;
struct hws_basic_entry *basic;
struct hws_diag_entry *diag;
- size_t pos = 0;
unsigned short bsdes, dsdes;
+ size_t pos = 0;
color_fprintf(stdout, color,
". ... s390 AUX data: size %zu bytes\n",
@@ -240,15 +380,414 @@ static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf,
s390_cpumsf_dump(sf, buf, len);
}
+#define S390_LPP_PID_MASK 0xffffffff
+
+static bool s390_cpumsf_make_event(size_t pos,
+ struct hws_basic_entry *basic,
+ struct s390_cpumsf_queue *sfq)
+{
+ struct perf_sample sample = {
+ .ip = basic->ia,
+ .pid = basic->hpp & S390_LPP_PID_MASK,
+ .tid = basic->hpp & S390_LPP_PID_MASK,
+ .cpumode = PERF_RECORD_MISC_CPUMODE_UNKNOWN,
+ .cpu = sfq->cpu,
+ .period = 1
+ };
+ union perf_event event;
+
+ memset(&event, 0, sizeof(event));
+ if (basic->CL == 1) /* Native LPAR mode */
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
+ : PERF_RECORD_MISC_KERNEL;
+ else if (basic->CL == 2) /* Guest kernel/user space */
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
+ : PERF_RECORD_MISC_GUEST_KERNEL;
+ else if (basic->gpp || basic->prim_asn != 0xffff)
+ /* Use heuristics on old hardware */
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
+ : PERF_RECORD_MISC_GUEST_KERNEL;
+ else
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
+ : PERF_RECORD_MISC_KERNEL;
+
+ event.sample.header.type = PERF_RECORD_SAMPLE;
+ event.sample.header.misc = sample.cpumode;
+ event.sample.header.size = sizeof(struct perf_event_header);
+
+ pr_debug4("%s pos:%#zx ip:%#lx P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
+ __func__, pos, sample.ip, basic->P, basic->CL, sample.pid,
+ sample.tid, sample.cpumode, sample.cpu);
+ if (perf_session__deliver_synth_event(sfq->sf->session, &event,
+ &sample)) {
+ pr_err("s390 Auxiliary Trace: failed to deliver event\n");
+ return false;
+ }
+ return true;
+}
+
+static unsigned long long get_trailer_time(const unsigned char *buf)
+{
+ struct hws_trailer_entry *te;
+ unsigned long long aux_time;
+
+ te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
+ - sizeof(*te));
+
+ if (!te->clock_base) /* TOD_CLOCK_BASE value missing */
+ return 0;
+
+ /* Correct calculation to convert time stamp in trailer entry to
+ * nano seconds (taken from arch/s390 function tod_to_ns()).
+ * TOD_CLOCK_BASE is stored in trailer entry member progusage2.
+ */
+ aux_time = trailer_timestamp(te) - te->progusage2;
+ aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9);
+ return aux_time;
+}
+
+/* Process the data samples of a single queue. The first parameter is a
+ * pointer to the queue, the second parameter is the time stamp. This
+ * is the time stamp
+ * - of the event that triggered this processing.
+ * - or the time stamp when the last proccesing of this queue stopped.
+ * In this case it stopped at a 4KB page boundary and record the
+ * position on where to continue processing on the next invocation
+ * (see buffer->use_data and buffer->use_size).
+ *
+ * When this function returns the second parameter is updated to
+ * reflect the time stamp of the last processed auxiliary data entry
+ * (taken from the trailer entry of that page). The caller uses this
+ * returned time stamp to record the last processed entry in this
+ * queue.
+ *
+ * The function returns:
+ * 0: Processing successful. The second parameter returns the
+ * time stamp from the trailer entry until which position
+ * processing took place. Subsequent calls resume from this
+ * position.
+ * <0: An error occurred during processing. The second parameter
+ * returns the maximum time stamp.
+ * >0: Done on this queue. The second parameter returns the
+ * maximum time stamp.
+ */
+static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts)
+{
+ struct s390_cpumsf *sf = sfq->sf;
+ unsigned char *buf = sfq->buffer->use_data;
+ size_t len = sfq->buffer->use_size;
+ struct hws_basic_entry *basic;
+ unsigned short bsdes, dsdes;
+ size_t pos = 0;
+ int err = 1;
+ u64 aux_ts;
+
+ if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
+ &dsdes)) {
+ *ts = ~0ULL;
+ return -1;
+ }
+
+ /* Get trailer entry time stamp and check if entries in
+ * this auxiliary page are ready for processing. If the
+ * time stamp of the first entry is too high, whole buffer
+ * can be skipped. In this case return time stamp.
+ */
+ aux_ts = get_trailer_time(buf);
+ if (!aux_ts) {
+ pr_err("[%#08lx] Invalid AUX trailer entry TOD clock base\n",
+ sfq->buffer->data_offset);
+ aux_ts = ~0ULL;
+ goto out;
+ }
+ if (aux_ts > *ts) {
+ *ts = aux_ts;
+ return 0;
+ }
+
+ while (pos < len) {
+ /* Handle Basic entry */
+ basic = (struct hws_basic_entry *)(buf + pos);
+ if (s390_cpumsf_make_event(pos, basic, sfq))
+ pos += bsdes;
+ else {
+ err = -EBADF;
+ goto out;
+ }
+
+ pos += dsdes; /* Skip diagnositic entry */
+
+ /* Check for trailer entry */
+ if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
+ pos = (pos + S390_CPUMSF_PAGESZ)
+ & ~(S390_CPUMSF_PAGESZ - 1);
+ /* Check existence of next page */
+ if (pos >= len)
+ break;
+ aux_ts = get_trailer_time(buf + pos);
+ if (!aux_ts) {
+ aux_ts = ~0ULL;
+ goto out;
+ }
+ if (aux_ts > *ts) {
+ *ts = aux_ts;
+ sfq->buffer->use_data += pos;
+ sfq->buffer->use_size -= pos;
+ return 0;
+ }
+ }
+ }
+out:
+ *ts = aux_ts;
+ sfq->buffer->use_size = 0;
+ sfq->buffer->use_data = NULL;
+ return err; /* Buffer completely scanned or error */
+}
+
+/* Run the s390 auxiliary trace decoder.
+ * Select the queue buffer to operate on, the caller already selected
+ * the proper queue, depending on second parameter 'ts'.
+ * This is the time stamp until which the auxiliary entries should
+ * be processed. This value is updated by called functions and
+ * returned to the caller.
+ *
+ * Resume processing in the current buffer. If there is no buffer
+ * get a new buffer from the queue and setup start position for
+ * processing.
+ * When a buffer is completely processed remove it from the queue
+ * before returning.
+ *
+ * This function returns
+ * 1: When the queue is empty. Second parameter will be set to
+ * maximum time stamp.
+ * 0: Normal processing done.
+ * <0: Error during queue buffer setup. This causes the caller
+ * to stop processing completely.
+ */
+static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
+ u64 *ts)
+{
+
+ struct auxtrace_buffer *buffer;
+ struct auxtrace_queue *queue;
+ int err;
+
+ queue = &sfq->sf->queues.queue_array[sfq->queue_nr];
+
+ /* Get buffer and last position in buffer to resume
+ * decoding the auxiliary entries. One buffer might be large
+ * and decoding might stop in between. This depends on the time
+ * stamp of the trailer entry in each page of the auxiliary
+ * data and the time stamp of the event triggering the decoding.
+ */
+ if (sfq->buffer == NULL) {
+ sfq->buffer = buffer = auxtrace_buffer__next(queue,
+ sfq->buffer);
+ if (!buffer) {
+ *ts = ~0ULL;
+ return 1; /* Processing done on this queue */
+ }
+ /* Start with a new buffer on this queue */
+ if (buffer->data) {
+ buffer->use_size = buffer->size;
+ buffer->use_data = buffer->data;
+ }
+ } else
+ buffer = sfq->buffer;
+
+ if (!buffer->data) {
+ int fd = perf_data__fd(sfq->sf->session->data);
+
+ buffer->data = auxtrace_buffer__get_data(buffer, fd);
+ if (!buffer->data)
+ return -ENOMEM;
+ buffer->use_size = buffer->size;
+ buffer->use_data = buffer->data;
+ }
+ pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
+ __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset,
+ buffer->size, buffer->use_size);
+ err = s390_cpumsf_samples(sfq, ts);
+
+ /* If non-zero, there is either an error (err < 0) or the buffer is
+ * completely done (err > 0). The error is unrecoverable, usually
+ * some descriptors could not be read successfully, so continue with
+ * the next buffer.
+ * In both cases the parameter 'ts' has been updated.
+ */
+ if (err) {
+ sfq->buffer = NULL;
+ list_del(&buffer->list);
+ auxtrace_buffer__free(buffer);
+ if (err > 0) /* Buffer done, no error */
+ err = 0;
+ }
+ return err;
+}
+
+static struct s390_cpumsf_queue *
+s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr)
+{
+ struct s390_cpumsf_queue *sfq;
+
+ sfq = zalloc(sizeof(struct s390_cpumsf_queue));
+ if (sfq == NULL)
+ return NULL;
+
+ sfq->sf = sf;
+ sfq->queue_nr = queue_nr;
+ sfq->cpu = -1;
+ return sfq;
+}
+
+static int s390_cpumsf_setup_queue(struct s390_cpumsf *sf,
+ struct auxtrace_queue *queue,
+ unsigned int queue_nr, u64 ts)
+{
+ struct s390_cpumsf_queue *sfq = queue->priv;
+
+ if (list_empty(&queue->head))
+ return 0;
+
+ if (sfq == NULL) {
+ sfq = s390_cpumsf_alloc_queue(sf, queue_nr);
+ if (!sfq)
+ return -ENOMEM;
+ queue->priv = sfq;
+
+ if (queue->cpu != -1)
+ sfq->cpu = queue->cpu;
+ }
+ return auxtrace_heap__add(&sf->heap, queue_nr, ts);
+}
+
+static int s390_cpumsf_setup_queues(struct s390_cpumsf *sf, u64 ts)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < sf->queues.nr_queues; i++) {
+ ret = s390_cpumsf_setup_queue(sf, &sf->queues.queue_array[i],
+ i, ts);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static int s390_cpumsf_update_queues(struct s390_cpumsf *sf, u64 ts)
+{
+ if (!sf->queues.new_data)
+ return 0;
+
+ sf->queues.new_data = false;
+ return s390_cpumsf_setup_queues(sf, ts);
+}
+
+static int s390_cpumsf_process_queues(struct s390_cpumsf *sf, u64 timestamp)
+{
+ unsigned int queue_nr;
+ u64 ts;
+ int ret;
+
+ while (1) {
+ struct auxtrace_queue *queue;
+ struct s390_cpumsf_queue *sfq;
+
+ if (!sf->heap.heap_cnt)
+ return 0;
+
+ if (sf->heap.heap_array[0].ordinal >= timestamp)
+ return 0;
+
+ queue_nr = sf->heap.heap_array[0].queue_nr;
+ queue = &sf->queues.queue_array[queue_nr];
+ sfq = queue->priv;
+
+ auxtrace_heap__pop(&sf->heap);
+ if (sf->heap.heap_cnt) {
+ ts = sf->heap.heap_array[0].ordinal + 1;
+ if (ts > timestamp)
+ ts = timestamp;
+ } else {
+ ts = timestamp;
+ }
+
+ ret = s390_cpumsf_run_decoder(sfq, &ts);
+ if (ret < 0) {
+ auxtrace_heap__add(&sf->heap, queue_nr, ts);
+ return ret;
+ }
+ if (!ret) {
+ ret = auxtrace_heap__add(&sf->heap, queue_nr, ts);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int s390_cpumsf_synth_error(struct s390_cpumsf *sf, int code, int cpu,
+ pid_t pid, pid_t tid, u64 ip)
+{
+ char msg[MAX_AUXTRACE_ERROR_MSG];
+ union perf_event event;
+ int err;
+
+ strncpy(msg, "Lost Auxiliary Trace Buffer", sizeof(msg) - 1);
+ auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
+ code, cpu, pid, tid, ip, msg);
+
+ err = perf_session__deliver_synth_event(sf->session, &event, NULL);
+ if (err)
+ pr_err("s390 Auxiliary Trace: failed to deliver error event,"
+ "error %d\n", err);
+ return err;
+}
+
+static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample)
+{
+ return s390_cpumsf_synth_error(sf, 1, sample->cpu,
+ sample->pid, sample->tid, 0);
+}
+
static int
s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
- union perf_event *event __maybe_unused,
- struct perf_sample *sample __maybe_unused,
- struct perf_tool *tool __maybe_unused)
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_tool *tool)
{
- return 0;
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+ u64 timestamp = sample->time;
+ int err = 0;
+
+ if (dump_trace)
+ return 0;
+
+ if (!tool->ordered_events) {
+ pr_err("s390 Auxiliary Trace requires ordered events\n");
+ return -EINVAL;
+ }
+
+ if (event->header.type == PERF_RECORD_AUX &&
+ event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
+ return s390_cpumsf_lost(sf, sample);
+
+ if (timestamp) {
+ err = s390_cpumsf_update_queues(sf, timestamp);
+ if (!err)
+ err = s390_cpumsf_process_queues(sf, timestamp);
+ }
+ return err;
}
+struct s390_cpumsf_synth {
+ struct perf_tool cpumsf_tool;
+ struct perf_session *session;
+};
+
static int
s390_cpumsf_process_auxtrace_event(struct perf_session *session,
union perf_event *event __maybe_unused,
@@ -263,6 +802,9 @@ s390_cpumsf_process_auxtrace_event(struct perf_session *session,
off_t data_offset;
int err;
+ if (sf->data_queued)
+ return 0;
+
if (perf_data__is_pipe(session->data)) {
data_offset = 0;
} else {
@@ -287,17 +829,21 @@ s390_cpumsf_process_auxtrace_event(struct perf_session *session,
return 0;
}
+static void s390_cpumsf_free_events(struct perf_session *session __maybe_unused)
+{
+}
+
static int s390_cpumsf_flush(struct perf_session *session __maybe_unused,
struct perf_tool *tool __maybe_unused)
{
return 0;
}
-static void s390_cpumsf_free_events(struct perf_session *session)
+static void s390_cpumsf_free_queues(struct perf_session *session)
{
struct s390_cpumsf *sf = container_of(session->auxtrace,
struct s390_cpumsf,
- auxtrace);
+ auxtrace);
struct auxtrace_queues *queues = &sf->queues;
unsigned int i;
@@ -313,7 +859,7 @@ static void s390_cpumsf_free(struct perf_session *session)
auxtrace);
auxtrace_heap__free(&sf->heap);
- s390_cpumsf_free_events(session);
+ s390_cpumsf_free_queues(session);
session->auxtrace = NULL;
free(sf);
}
@@ -326,6 +872,19 @@ static int s390_cpumsf_get_type(const char *cpuid)
return (ret == 1) ? family : 0;
}
+/* Check itrace options set on perf report command.
+ * Return true, if none are set or all options specified can be
+ * handled on s390.
+ * Return false otherwise.
+ */
+static bool check_auxtrace_itrace(struct itrace_synth_opts *itops)
+{
+ if (!itops || !itops->set)
+ return true;
+ pr_err("No --itrace options supported\n");
+ return false;
+}
+
int s390_cpumsf_process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
@@ -340,6 +899,11 @@ int s390_cpumsf_process_auxtrace_info(union perf_event *event,
if (sf == NULL)
return -ENOMEM;
+ if (!check_auxtrace_itrace(session->itrace_synth_opts)) {
+ err = -EINVAL;
+ goto err_free;
+ }
+
err = auxtrace_queues__init(&sf->queues);
if (err)
goto err_free;
@@ -357,8 +921,21 @@ int s390_cpumsf_process_auxtrace_info(union perf_event *event,
sf->auxtrace.free = s390_cpumsf_free;
session->auxtrace = &sf->auxtrace;
+ if (dump_trace)
+ return 0;
+
+ err = auxtrace_queues__process_index(&sf->queues, session);
+ if (err)
+ goto err_free_queues;
+
+ if (sf->queues.populated)
+ sf->data_queued = true;
+
return 0;
+err_free_queues:
+ auxtrace_queues__free(&sf->queues);
+ session->auxtrace = NULL;
err_free:
free(sf);
return err;
--
2.17.0
Em Thu, Aug 02, 2018 at 09:46:20AM +0200, Thomas Richter escreveu:
> Add initial support for s390 auxiliary traces using the
> CPU-Measurement Sampling Facility.
Could you please provide one or two paragraphs explaining what is this
"CPU-Measurement Sampling Facility", in which hardware this is available
(all s/390 hardware has it? Just the 64-bit model(s)?) and provide a
public URL for people interested in further reading?
- Arnaldo
> Support and ignore PERF_REPORT_AUXTRACE_INFO records
> in the perf data file. Later patches will show the contents
> of the auxiliary traces.
>
> Setup the auxtrace queues and data structures for s390.
> A raw dump of the perf.data file now does not show
> an error when an auxtrace event is encountered.
>
> Output before:
> [root@s35lp76 perf]# ./perf report -D -i perf.data.auxtrace
> 0x128 [0x10]: failed to process type: 70
> Error:
> failed to process sample
>
> 0x128 [0x10]: event: 70
> .
> . ... raw event: size 16 bytes
> . 0000: 00 00 00 46 00 00 00 10 00 00 00 00 00 00 00 00 ...F............
>
> 0x128 [0x10]: PERF_RECORD_AUXTRACE_INFO type: 0
> [root@s35lp76 perf]#
>
> Output after:
> # ./perf report -D -i perf.data.auxtrace |fgrep PERF_RECORD_AUXTRACE
> 0 0 0x128 [0x10]: PERF_RECORD_AUXTRACE_INFO type: 5
> 0 0 0x25a66 [0x30]: PERF_RECORD_AUXTRACE size: 0x40000
> offset: 0 ref: 0 idx: 4 tid: -1 cpu: 4
> ....
>
> Signed-off-by: Thomas Richter <[email protected]>
> Reviewed-by: Hendrik Brueckner <[email protected]>
> ---
> tools/perf/arch/s390/util/auxtrace.c | 1 +
> tools/perf/util/Build | 1 +
> tools/perf/util/auxtrace.c | 3 +
> tools/perf/util/auxtrace.h | 1 +
> tools/perf/util/s390-cpumsf.c | 123 +++++++++++++++++++++++++++
> tools/perf/util/s390-cpumsf.h | 21 +++++
> 6 files changed, 150 insertions(+)
> create mode 100644 tools/perf/util/s390-cpumsf.c
> create mode 100644 tools/perf/util/s390-cpumsf.h
>
> diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c
> index 3afe8256eff2..44c857388897 100644
> --- a/tools/perf/arch/s390/util/auxtrace.c
> +++ b/tools/perf/arch/s390/util/auxtrace.c
> @@ -30,6 +30,7 @@ cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused,
> struct auxtrace_info_event *auxtrace_info __maybe_unused,
> size_t priv_size __maybe_unused)
> {
> + auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF;
> return 0;
> }
>
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index b604ef334dc9..7efe15b9618d 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
> libperf-$(CONFIG_AUXTRACE) += intel-bts.o
> libperf-$(CONFIG_AUXTRACE) += arm-spe.o
> libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
> +libperf-$(CONFIG_AUXTRACE) += s390-cpumsf.o
>
> ifdef CONFIG_LIBOPENCSD
> libperf-$(CONFIG_AUXTRACE) += cs-etm.o
> diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> index d056447520a2..ae8c37b219c9 100644
> --- a/tools/perf/util/auxtrace.c
> +++ b/tools/perf/util/auxtrace.c
> @@ -56,6 +56,7 @@
> #include "intel-pt.h"
> #include "intel-bts.h"
> #include "arm-spe.h"
> +#include "s390-cpumsf.h"
>
> #include "sane_ctype.h"
> #include "symbol/kallsyms.h"
> @@ -920,6 +921,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
> return arm_spe_process_auxtrace_info(event, session);
> case PERF_AUXTRACE_CS_ETM:
> return cs_etm__process_auxtrace_info(event, session);
> + case PERF_AUXTRACE_S390_CPUMSF:
> + return s390_cpumsf_process_auxtrace_info(event, session);
> case PERF_AUXTRACE_UNKNOWN:
> default:
> return -EINVAL;
> diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
> index e731f55da072..71fc3bd74299 100644
> --- a/tools/perf/util/auxtrace.h
> +++ b/tools/perf/util/auxtrace.h
> @@ -44,6 +44,7 @@ enum auxtrace_type {
> PERF_AUXTRACE_INTEL_BTS,
> PERF_AUXTRACE_CS_ETM,
> PERF_AUXTRACE_ARM_SPE,
> + PERF_AUXTRACE_S390_CPUMSF,
> };
>
> enum itrace_period_type {
> diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
> new file mode 100644
> index 000000000000..e9a5ea21dbbf
> --- /dev/null
> +++ b/tools/perf/util/s390-cpumsf.c
> @@ -0,0 +1,123 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright IBM Corp. 2018
> + * Auxtrace support for s390 CPU-Measurement Sampling Facility
> + *
> + * Author(s): Thomas Richter <[email protected]>
> + */
> +
> +#include <endian.h>
> +#include <errno.h>
> +#include <byteswap.h>
> +#include <inttypes.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/bitops.h>
> +#include <linux/log2.h>
> +
> +#include "cpumap.h"
> +#include "color.h"
> +#include "evsel.h"
> +#include "evlist.h"
> +#include "machine.h"
> +#include "session.h"
> +#include "util.h"
> +#include "thread.h"
> +#include "debug.h"
> +#include "auxtrace.h"
> +#include "s390-cpumsf.h"
> +
> +struct s390_cpumsf {
> + struct auxtrace auxtrace;
> + struct auxtrace_queues queues;
> + struct auxtrace_heap heap;
> + struct perf_session *session;
> + struct machine *machine;
> + u32 auxtrace_type;
> + u32 pmu_type;
> +};
> +
> +static int
> +s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
> + union perf_event *event __maybe_unused,
> + struct perf_sample *sample __maybe_unused,
> + struct perf_tool *tool __maybe_unused)
> +{
> + return 0;
> +}
> +
> +static int
> +s390_cpumsf_process_auxtrace_event(struct perf_session *session __maybe_unused,
> + union perf_event *event __maybe_unused,
> + struct perf_tool *tool __maybe_unused)
> +{
> + return 0;
> +}
> +
> +static int s390_cpumsf_flush(struct perf_session *session __maybe_unused,
> + struct perf_tool *tool __maybe_unused)
> +{
> + return 0;
> +}
> +
> +static void s390_cpumsf_free_events(struct perf_session *session)
> +{
> + struct s390_cpumsf *sf = container_of(session->auxtrace,
> + struct s390_cpumsf,
> + auxtrace);
> + struct auxtrace_queues *queues = &sf->queues;
> + unsigned int i;
> +
> + for (i = 0; i < queues->nr_queues; i++)
> + zfree(&queues->queue_array[i].priv);
> + auxtrace_queues__free(queues);
> +}
> +
> +static void s390_cpumsf_free(struct perf_session *session)
> +{
> + struct s390_cpumsf *sf = container_of(session->auxtrace,
> + struct s390_cpumsf,
> + auxtrace);
> +
> + auxtrace_heap__free(&sf->heap);
> + s390_cpumsf_free_events(session);
> + session->auxtrace = NULL;
> + free(sf);
> +}
> +
> +int s390_cpumsf_process_auxtrace_info(union perf_event *event,
> + struct perf_session *session)
> +{
> + struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
> + struct s390_cpumsf *sf;
> + int err;
> +
> + if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event))
> + return -EINVAL;
> +
> + sf = zalloc(sizeof(struct s390_cpumsf));
> + if (sf == NULL)
> + return -ENOMEM;
> +
> + err = auxtrace_queues__init(&sf->queues);
> + if (err)
> + goto err_free;
> +
> + sf->session = session;
> + sf->machine = &session->machines.host; /* No kvm support */
> + sf->auxtrace_type = auxtrace_info->type;
> + sf->pmu_type = PERF_TYPE_RAW;
> +
> + sf->auxtrace.process_event = s390_cpumsf_process_event;
> + sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event;
> + sf->auxtrace.flush_events = s390_cpumsf_flush;
> + sf->auxtrace.free_events = s390_cpumsf_free_events;
> + sf->auxtrace.free = s390_cpumsf_free;
> + session->auxtrace = &sf->auxtrace;
> +
> + return 0;
> +
> +err_free:
> + free(sf);
> + return err;
> +}
> diff --git a/tools/perf/util/s390-cpumsf.h b/tools/perf/util/s390-cpumsf.h
> new file mode 100644
> index 000000000000..fb64d100555c
> --- /dev/null
> +++ b/tools/perf/util/s390-cpumsf.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright IBM Corp. 2018
> + * Auxtrace support for s390 CPU-Measurement Sampling Facility
> + *
> + * Author(s): Thomas Richter <[email protected]>
> + */
> +
> +#ifndef INCLUDE__PERF_S390_CPUMSF_H
> +#define INCLUDE__PERF_S390_CPUMSF_H
> +
> +union perf_event;
> +struct perf_session;
> +struct perf_pmu;
> +
> +struct auxtrace_record *
> +s390_cpumsf_recording_init(int *err, struct perf_pmu *s390_cpumsf_pmu);
> +
> +int s390_cpumsf_process_auxtrace_info(union perf_event *event,
> + struct perf_session *session);
> +#endif
> --
> 2.17.0
Arnaldo,
On Thu, Aug 02, 2018 at 09:49:09AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Thu, Aug 02, 2018 at 09:46:20AM +0200, Thomas Richter escreveu:
> > Add initial support for s390 auxiliary traces using the
> > CPU-Measurement Sampling Facility.
>
> Could you please provide one or two paragraphs explaining what is this
> "CPU-Measurement Sampling Facility", in which hardware this is available
> (all s/390 hardware has it? Just the 64-bit model(s)?) and provide a
> public URL for people interested in further reading?
The CPU-Measurement Facility (CPU-MF) provides a set of functions to obtain
performance information on the mainframe. Basically, it was introduced
with System z10 years ago for the z/Architecture, that means, 64-bit.
For Linux, there are two facilities of interest, counter facility and sampling
facility. The counter facility provides hardware counters for instructions,
cycles, crypto-activities, and many more.
The sampling facility is a hardware sampler that when started will write
samples at a particular interval into a sampling buffer. At some point,
for example, if a sample block is full, it generates an interrupt to collect
samples (while the sampler continues to run).
Few years ago, I started to provide the a perf PMU to use the counter
and sampling facilities. Recently, the device driver was updated to also
"export" the sampling buffer into the AUX area. Thomas now completed the
related perf work to interpret and process these AUX data.
If people are more interested in the sampling facility, they can have a
look into:
- The Load-Program-Parameter and the CPU-Measurement Facilities, SA23-2260-05
http://www-01.ibm.com/support/docview.wss?uid=isg26fcd1cc32246f4c8852574ce0044734a
and to learn how-to use it for Linux on Z, have look at chapter 54,
"Using the CPU-measurement facilities" in the:
- Device Drivers, Features, and Commands, SC33-8411-34
http://public.dhe.ibm.com/software/dw/linux390/docu/l416dd34.pdf
Thanks and kind regards,
Hendrik
Em Fri, Aug 03, 2018 at 12:07:58PM +0200, Hendrik Brueckner escreveu:
> Arnaldo,
>
> On Thu, Aug 02, 2018 at 09:49:09AM -0300, Arnaldo Carvalho de Melo wrote:
> > Em Thu, Aug 02, 2018 at 09:46:20AM +0200, Thomas Richter escreveu:
> > > Add initial support for s390 auxiliary traces using the
> > > CPU-Measurement Sampling Facility.
> >
> > Could you please provide one or two paragraphs explaining what is this
> > "CPU-Measurement Sampling Facility", in which hardware this is available
> > (all s/390 hardware has it? Just the 64-bit model(s)?) and provide a
> > public URL for people interested in further reading?
>
> The CPU-Measurement Facility (CPU-MF) provides a set of functions to obtain
> performance information on the mainframe. Basically, it was introduced
> with System z10 years ago for the z/Architecture, that means, 64-bit.
> For Linux, there are two facilities of interest, counter facility and sampling
> facility. The counter facility provides hardware counters for instructions,
> cycles, crypto-activities, and many more.
>
> The sampling facility is a hardware sampler that when started will write
> samples at a particular interval into a sampling buffer. At some point,
> for example, if a sample block is full, it generates an interrupt to collect
> samples (while the sampler continues to run).
>
> Few years ago, I started to provide the a perf PMU to use the counter
> and sampling facilities. Recently, the device driver was updated to also
> "export" the sampling buffer into the AUX area. Thomas now completed the
> related perf work to interpret and process these AUX data.
>
> If people are more interested in the sampling facility, they can have a
> look into:
>
> - The Load-Program-Parameter and the CPU-Measurement Facilities, SA23-2260-05
> http://www-01.ibm.com/support/docview.wss?uid=isg26fcd1cc32246f4c8852574ce0044734a
>
> and to learn how-to use it for Linux on Z, have look at chapter 54,
> "Using the CPU-measurement facilities" in the:
>
> - Device Drivers, Features, and Commands, SC33-8411-34
> http://public.dhe.ibm.com/software/dw/linux390/docu/l416dd34.pdf
-----------------------
Thanks a lot, I added this to the first commit, people investigating
this should be able to find that when doing research about the
implementation details.
- Arnaldo
Thomas Richter <[email protected]> writes:
> Add support for s390 auxiliary trace support.
> Use 'perf record -e rbd000' to create the perf.data file.
> The event also has the symbolic name SF_CYCLES_BASIC_DIAG,
> using 'perf record -e SF_CYCLES_BASIC_DIAG' is equivalent.
...
>
> Signed-off-by: Thomas Richter <[email protected]>
> Reviewed-by: Hendrik Brueckner <[email protected]>
> ---
> tools/perf/util/s390-cpumsf-kernel.h | 71 ++++++++
> tools/perf/util/s390-cpumsf.c | 244 ++++++++++++++++++++++++++-
> 2 files changed, 314 insertions(+), 1 deletion(-)
> create mode 100644 tools/perf/util/s390-cpumsf-kernel.h
I'm seeing a build break on ppc64le which seems to be caused by this
commit (I haven't bisected):
util/s390-cpumsf.c: In function ‘trailer_timestamp’:
util/s390-cpumsf.c:222:2: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
return *((unsigned long long *) &te->timestamp[te->t]);
^
And on powerpc big endian:
In file included from util/cpumap.h:10:0,
from util/s390-cpumsf.c:150:
util/s390-cpumsf.c: In function ‘s390_cpumsf_basic_show’:
util/s390-cpumsf.c:187:10: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t {aka unsigned int}’ [-Werror=format=]
pr_err("Invalid AUX trace basic entry [%#08lx]\n", pos);
^
cheers
On 08/08/2018 05:37 AM, [email protected] wrote:
> Thomas Richter <[email protected]> writes:
>> Add support for s390 auxiliary trace support.
>> Use 'perf record -e rbd000' to create the perf.data file.
>> The event also has the symbolic name SF_CYCLES_BASIC_DIAG,
>> using 'perf record -e SF_CYCLES_BASIC_DIAG' is equivalent.
> ...
>>
>> Signed-off-by: Thomas Richter <[email protected]>
>> Reviewed-by: Hendrik Brueckner <[email protected]>
>> ---
>> tools/perf/util/s390-cpumsf-kernel.h | 71 ++++++++
>> tools/perf/util/s390-cpumsf.c | 244 ++++++++++++++++++++++++++-
>> 2 files changed, 314 insertions(+), 1 deletion(-)
>> create mode 100644 tools/perf/util/s390-cpumsf-kernel.h
>
>
> I'm seeing a build break on ppc64le which seems to be caused by this
> commit (I haven't bisected):
>
> util/s390-cpumsf.c: In function ‘trailer_timestamp’:
> util/s390-cpumsf.c:222:2: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
> return *((unsigned long long *) &te->timestamp[te->t]);
> ^
>
>
> And on powerpc big endian:
> In file included from util/cpumap.h:10:0,
> from util/s390-cpumsf.c:150:
> util/s390-cpumsf.c: In function ‘s390_cpumsf_basic_show’:
> util/s390-cpumsf.c:187:10: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t {aka unsigned int}’ [-Werror=format=]
> pr_err("Invalid AUX trace basic entry [%#08lx]\n", pos);
> ^
>
> cheers
>
Can you please try this patch. Thanks a lot
--
Thomas Richter, Dept 3303, IBM s390 Linux Development, Boeblingen, Germany
--
Vorsitzende des Aufsichtsrats: Martina Koederitz
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen / Registergericht: Amtsgericht Stuttgart, HRB 243294
Em Wed, Aug 08, 2018 at 08:39:58AM +0200, Thomas-Mich Richter escreveu:
> On 08/08/2018 05:37 AM, [email protected] wrote:
> > Thomas Richter <[email protected]> writes:
> >> Add support for s390 auxiliary trace support.
> >> Use 'perf record -e rbd000' to create the perf.data file.
> >> The event also has the symbolic name SF_CYCLES_BASIC_DIAG,
> >> using 'perf record -e SF_CYCLES_BASIC_DIAG' is equivalent.
> > ...
> >>
> >> Signed-off-by: Thomas Richter <[email protected]>
> >> Reviewed-by: Hendrik Brueckner <[email protected]>
> >> ---
> >> tools/perf/util/s390-cpumsf-kernel.h | 71 ++++++++
> >> tools/perf/util/s390-cpumsf.c | 244 ++++++++++++++++++++++++++-
> >> 2 files changed, 314 insertions(+), 1 deletion(-)
> >> create mode 100644 tools/perf/util/s390-cpumsf-kernel.h
> >
> >
> > I'm seeing a build break on ppc64le which seems to be caused by this
> > commit (I haven't bisected):
> >
> > util/s390-cpumsf.c: In function ‘trailer_timestamp’:
> > util/s390-cpumsf.c:222:2: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
> > return *((unsigned long long *) &te->timestamp[te->t]);
> > ^
> >
> >
> > And on powerpc big endian:
> > In file included from util/cpumap.h:10:0,
> > from util/s390-cpumsf.c:150:
> > util/s390-cpumsf.c: In function ‘s390_cpumsf_basic_show’:
> > util/s390-cpumsf.c:187:10: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t {aka unsigned int}’ [-Werror=format=]
> > pr_err("Invalid AUX trace basic entry [%#08lx]\n", pos);
> > ^
> >
> > cheers
> >
>
> Can you please try this patch. Thanks a lot
Ok, this was making the build fail as well on some containers here:
1 37.95 alpine:3.4 : gcc (Alpine 5.3.0) 5.3.0
CC /tmp/build/perf/util/s390-cpumsf.o
LD /tmp/build/perf/util/scripting-engines/libperf-in.o
CC /tmp/build/perf/util/parse-branch-options.o
CC /tmp/build/perf/util/dump-insn.o
util/s390-cpumsf.c: In function 'trailer_timestamp':
util/s390-cpumsf.c:222:2: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
return *((unsigned long long *) &te->timestamp[te->t]);
^
2 48.46 alpine:3.5 : gcc (Alpine 6.2.1) 6.2.1 20160822
CC /tmp/build/perf/util/parse-branch-options.o
util/s390-cpumsf.c: In function 'trailer_timestamp':
util/s390-cpumsf.c:222:2: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
return *((unsigned long long *) &te->timestamp[te->t]);
^~~~~~
CC /tmp/build/perf/util/dump-insn.o
---------
I stopped at this point when this report/patch resurfaced in my mind, so
I came back and folded this fix into the cset introducing the problem
since it hasn't gone Ingo's way, so that we can keep this bisectable
when upstream.
Thanks guys!
- Arnaldo
Em Wed, Aug 08, 2018 at 12:53:28PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Wed, Aug 08, 2018 at 08:39:58AM +0200, Thomas-Mich Richter escreveu:
> > On 08/08/2018 05:37 AM, [email protected] wrote:
> > > Thomas Richter <[email protected]> writes:
> > >> Add support for s390 auxiliary trace support.
> > >> Use 'perf record -e rbd000' to create the perf.data file.
> > >> The event also has the symbolic name SF_CYCLES_BASIC_DIAG,
> > >> using 'perf record -e SF_CYCLES_BASIC_DIAG' is equivalent.
> > > ...
> > >>
> > >> Signed-off-by: Thomas Richter <[email protected]>
> > >> Reviewed-by: Hendrik Brueckner <[email protected]>
> > >> ---
> > >> tools/perf/util/s390-cpumsf-kernel.h | 71 ++++++++
> > >> tools/perf/util/s390-cpumsf.c | 244 ++++++++++++++++++++++++++-
> > >> 2 files changed, 314 insertions(+), 1 deletion(-)
> > >> create mode 100644 tools/perf/util/s390-cpumsf-kernel.h
> > >
> > >
> > > I'm seeing a build break on ppc64le which seems to be caused by this
> > > commit (I haven't bisected):
> > >
> > > util/s390-cpumsf.c: In function ‘trailer_timestamp’:
> > > util/s390-cpumsf.c:222:2: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
> > > return *((unsigned long long *) &te->timestamp[te->t]);
> > > ^
> > >
> > >
> > > And on powerpc big endian:
> > > In file included from util/cpumap.h:10:0,
> > > from util/s390-cpumsf.c:150:
> > > util/s390-cpumsf.c: In function ‘s390_cpumsf_basic_show’:
> > > util/s390-cpumsf.c:187:10: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t {aka unsigned int}’ [-Werror=format=]
> > > pr_err("Invalid AUX trace basic entry [%#08lx]\n", pos);
> > > ^
> > >
> > > cheers
> > >
> >
> > Can you please try this patch. Thanks a lot
>
> Ok, this was making the build fail as well on some containers here:
Ok, failed in another container:
11 centos:6 : gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18)
CC /tmp/build/perf/tests/sample-parsing.o
cc1: warnings being treated as errors
In file included from util/s390-cpumsf.c:161:
util/s390-cpumsf-kernel.h:16: error: packed attribute is unnecessary for 'def'
util/s390-cpumsf-kernel.h:25: error: packed attribute is unnecessary for 'CL'
util/s390-cpumsf-kernel.h:28: error: packed attribute is unnecessary for 'ia'
util/s390-cpumsf-kernel.h:29: error: packed attribute is unnecessary for 'gpp'
util/s390-cpumsf-kernel.h:30: error: packed attribute is unnecessary for 'hpp'
util/s390-cpumsf-kernel.h:34: error: packed attribute is unnecessary for 'def'
mv: cannot stat `/tmp/build/perf/util/.s390-cpumsf.o.tmp': No such file or directory
make[4]: *** [/tmp/build/perf/util/s390-cpumsf.o] Error 1
For reference, this is the current output of the tests so far, that I'll
let running while I try to figure out this case:
[root@seventh ~]# time dm
1 37.95 alpine:3.4 : Ok gcc (Alpine 5.3.0) 5.3.0
2 48.46 alpine:3.5 : Ok gcc (Alpine 6.2.1) 6.2.1 20160822
3 43.18 alpine:3.6 : Ok gcc (Alpine 6.3.0) 6.3.0
4 46.87 alpine:3.7 : Ok gcc (Alpine 6.4.0) 6.4.0
5 85.35 alpine:edge : Ok gcc (Alpine 6.4.0) 6.4.0
6 36.86 amazonlinux:1 : Ok gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28)
7 41.37 amazonlinux:2 : Ok gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
8 30.61 android-ndk:r12b-arm : Ok arm-linux-androideabi-gcc (GCC) 4.9.x 20150123 (prerelease)
9 27.69 android-ndk:r15c-arm : Ok arm-linux-androideabi-gcc (GCC) 4.9.x 20150123 (prerelease)
10 26.45 centos:5 : Ok gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-55)
11 20.70 centos:6 : FAIL gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-23)
12 39.16 centos:7 : Ok gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28)
13 34.18 debian:7 : Ok gcc (Debian 4.7.2-5) 4.7.2
14 37.12 debian:8 : Ok gcc (Debian 4.9.2-10+deb8u1) 4.9.2
15: debian:9
Em Wed, Aug 08, 2018 at 12:59:21PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Wed, Aug 08, 2018 at 12:53:28PM -0300, Arnaldo Carvalho de Melo escreveu:
> > Em Wed, Aug 08, 2018 at 08:39:58AM +0200, Thomas-Mich Richter escreveu:
> > > On 08/08/2018 05:37 AM, [email protected] wrote:
> > > > Thomas Richter <[email protected]> writes:
> > > >> Add support for s390 auxiliary trace support.
> > > >> Use 'perf record -e rbd000' to create the perf.data file.
> > > >> The event also has the symbolic name SF_CYCLES_BASIC_DIAG,
> > > >> using 'perf record -e SF_CYCLES_BASIC_DIAG' is equivalent.
> > > > ...
> > > >>
> > > >> Signed-off-by: Thomas Richter <[email protected]>
> > > >> Reviewed-by: Hendrik Brueckner <[email protected]>
> > > >> ---
> > > >> tools/perf/util/s390-cpumsf-kernel.h | 71 ++++++++
> > > >> tools/perf/util/s390-cpumsf.c | 244 ++++++++++++++++++++++++++-
> > > >> 2 files changed, 314 insertions(+), 1 deletion(-)
> > > >> create mode 100644 tools/perf/util/s390-cpumsf-kernel.h
> > > >
> > > >
> > > > I'm seeing a build break on ppc64le which seems to be caused by this
> > > > commit (I haven't bisected):
> > > >
> > > > util/s390-cpumsf.c: In function ‘trailer_timestamp’:
> > > > util/s390-cpumsf.c:222:2: error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]
> > > > return *((unsigned long long *) &te->timestamp[te->t]);
> > > > ^
> > > >
> > > >
> > > > And on powerpc big endian:
> > > > In file included from util/cpumap.h:10:0,
> > > > from util/s390-cpumsf.c:150:
> > > > util/s390-cpumsf.c: In function ‘s390_cpumsf_basic_show’:
> > > > util/s390-cpumsf.c:187:10: error: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 4 has type ‘size_t {aka unsigned int}’ [-Werror=format=]
> > > > pr_err("Invalid AUX trace basic entry [%#08lx]\n", pos);
> > > > ^
> > > >
> > > > cheers
> > > >
> > >
> > > Can you please try this patch. Thanks a lot
> >
> > Ok, this was making the build fail as well on some containers here:
>
> Ok, failed in another container:
>
> 11 centos:6 : gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18)
>
> CC /tmp/build/perf/tests/sample-parsing.o
> cc1: warnings being treated as errors
> In file included from util/s390-cpumsf.c:161:
> util/s390-cpumsf-kernel.h:16: error: packed attribute is unnecessary for 'def'
> util/s390-cpumsf-kernel.h:25: error: packed attribute is unnecessary for 'CL'
> util/s390-cpumsf-kernel.h:28: error: packed attribute is unnecessary for 'ia'
> util/s390-cpumsf-kernel.h:29: error: packed attribute is unnecessary for 'gpp'
> util/s390-cpumsf-kernel.h:30: error: packed attribute is unnecessary for 'hpp'
> util/s390-cpumsf-kernel.h:34: error: packed attribute is unnecessary for 'def'
> mv: cannot stat `/tmp/build/perf/util/.s390-cpumsf.o.tmp': No such file or directory
> make[4]: *** [/tmp/build/perf/util/s390-cpumsf.o] Error 1
So, this is how it shows using that __packed you have:
[acme@seventh perf]$ pahole -C hws_basic_entry ~/bin/perf
struct hws_basic_entry {
unsigned int def:16; /* 0:16 4 */
unsigned int R:4; /* 0:12 4 */
unsigned int U:4; /* 0: 8 4 */
unsigned int z:2; /* 0: 6 4 */
unsigned int T:1; /* 0: 5 4 */
unsigned int W:1; /* 0: 4 4 */
unsigned int P:1; /* 0: 3 4 */
unsigned int AS:2; /* 0: 1 4 */
unsigned int I:1; /* 0: 0 4 */
unsigned int CL:2; /* 4:30 4 */
unsigned int prim_asn:16; /* 4: 0 4 */
/* XXX 14 bits hole, try to pack */
long long unsigned int ia; /* 8 8 */
long long unsigned int gpp; /* 16 8 */
long long unsigned int hpp; /* 24 8 */
/* size: 32, cachelines: 1, members: 14 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
[acme@seventh perf]$
And:
[acme@seventh perf]$ pahole -C hws_diag_entry ~/bin/perf
struct hws_diag_entry {
unsigned int def:16; /* 0:16 4 */
unsigned int R:15; /* 0: 1 4 */
unsigned int I:1; /* 0: 0 4 */
u8 data[0]; /* 4 0 */
/* size: 4, cachelines: 1, members: 4 */
/* last cacheline: 4 bytes */
};
[acme@seventh perf]$
Now, if we apply this patch:
[acme@seventh perf]$ pahole -C hws_basic_entry ~/bin/perf
struct hws_basic_entry {
unsigned int def:16; /* 0:16 4 */
unsigned int R:4; /* 0:12 4 */
unsigned int U:4; /* 0: 8 4 */
unsigned int z:2; /* 0: 6 4 */
unsigned int T:1; /* 0: 5 4 */
unsigned int W:1; /* 0: 4 4 */
unsigned int P:1; /* 0: 3 4 */
unsigned int AS:2; /* 0: 1 4 */
unsigned int I:1; /* 0: 0 4 */
unsigned int CL:2; /* 4:30 4 */
unsigned int prim_asn:16; /* 4: 0 4 */
/* XXX 14 bits hole, try to pack */
long long unsigned int ia; /* 8 8 */
long long unsigned int gpp; /* 16 8 */
long long unsigned int hpp; /* 24 8 */
/* size: 32, cachelines: 1, members: 14 */
/* bit holes: 1, sum bit holes: 14 bits */
/* last cacheline: 32 bytes */
};
[acme@seventh perf]$
See, no need for packing, that old gcc version is right, and the other
struct:
[acme@seventh perf]$ pahole -C hws_diag_entry ~/bin/perf
struct hws_diag_entry {
unsigned int def:16; /* 0:16 4 */
unsigned int R:15; /* 0: 1 4 */
unsigned int I:1; /* 0: 0 4 */
u8 data[0]; /* 4 0 */
/* size: 4, cachelines: 1, members: 4 */
/* last cacheline: 4 bytes */
};
[acme@seventh perf]$
No need for __packed.
I'm removing that to avoid having this failling in compilers that have
such a warning, since we default to Werror.
Holler if there is something I'missing :-)
- Arnaldo
Em Wed, Aug 08, 2018 at 01:08:43PM -0300, Arnaldo Carvalho de Melo escreveu:
> No need for __packed.
> I'm removing that to avoid having this failling in compilers that have
> such a warning, since we default to Werror.
> Holler if there is something I'missing :-)
BTW:
15 68.32 debian:9 : Ok gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
16 105.45 debian:experimental : Ok gcc (Debian 8.2.0-1) 8.2.0
17 39.76 debian:experimental-x-arm64 : Ok aarch64-linux-gnu-gcc (Debian 8.1.0-12) 8.1.0
18 18.40 debian:experimental-x-mips : FAIL mips-linux-gnu-gcc (Debian 8.1.0-12) 8.1.0
19 18.30 debian:experimental-x-mips64 : FAIL mips64-linux-gnuabi64-gcc (Debian 7.3.0-18) 7.3.0
20 20.58 debian:experimental-x-mipsel : FAIL mipsel-linux-gnu-gcc (Debian 8.1.0-12) 8.1.0
21 38.90 fedora:20 : Ok gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
22 39.14 fedora:21 : Ok gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)
23 38.65 fedora:22 : Ok gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
24 41.29 fedora:23 : Ok gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
25 40.03 fedora:24 : Ok gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1)
26 17.49 fedora:24-x-ARC-uClibc : FAIL arc-linux-gcc (ARCompact ISA Linux uClibc toolchain 2017.09-rc2) 7.1.1 20170710
27 94.44 fedora:25 : Ok gcc (GCC) 6.4.1 20170727 (Red Hat 6.4.1-1)
28 104.96 fedora:26 : Ok gcc (GCC) 7.3.1 20180130 (Red Hat 7.3.1-2)
29 107.23 fedora:27 : Ok gcc (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
30 120.34 fedora:28 : Ok gcc (GCC) 8.1.1 20180502 (Red Hat 8.1.1-1)
Lets see, different warning, much newer GCC version (8.1.0), and additional
errors in that file, I'll remove the __packed and see whats left, see at the
end, out of curiosity, for (ARCompact ISA Linux uClibc toolchain 2017.09-rc2),
older compiler (7.1.1) but same warnings/errors:
18 18.40 debian:experimental-x-mips : FAIL mips-linux-gnu-gcc (Debian 8.1.0-12) 8.1.0
CC /tmp/build/perf/util/s390-cpumsf.o
CC /tmp/build/perf/util/parse-branch-options.o
In file included from util/s390-cpumsf.c:161:
util/s390-cpumsf-kernel.h:16:15: error: packed attribute causes inefficient alignment for 'def' [-Werror=attributes]
unsigned int def:16; /* 0-15 Data Entry Format */
^~~
util/s390-cpumsf-kernel.h:25:15: error: packed attribute causes inefficient alignment for 'CL' [-Werror=attributes]
unsigned int CL:2; /* 32-33 Configuration Level */
^~
util/s390-cpumsf-kernel.h:28:21: error: packed attribute causes inefficient alignment for 'ia' [-Werror=attributes]
unsigned long long ia; /* Instruction Address */
^~
util/s390-cpumsf-kernel.h:29:21: error: packed attribute causes inefficient alignment for 'gpp' [-Werror=attributes]
unsigned long long gpp; /* Guest Program Parameter */
^~~
util/s390-cpumsf-kernel.h:30:21: error: packed attribute causes inefficient alignment for 'hpp' [-Werror=attributes]
unsigned long long hpp; /* Host Program Parameter */
^~~
util/s390-cpumsf-kernel.h:34:15: error: packed attribute causes inefficient alignment for 'def' [-Werror=attributes]
unsigned int def:16; /* 0-15 Data Entry Format */
^~~
In file included from util/cpumap.h:10,
from util/s390-cpumsf.c:150:
util/s390-cpumsf.c: In function 's390_cpumsf_diag_show':
util/s390-cpumsf.c:208:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Werror=format=]
pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
util/s390-cpumsf.c:208:3: note: in expansion of macro 'pr_err'
pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
^~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_trailer_show':
util/s390-cpumsf.c:233:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Werror=format=]
pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
util/s390-cpumsf.c:233:3: note: in expansion of macro 'pr_err'
pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
^~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_make_event':
util/s390-cpumsf.c:421:12: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'u64' {aka 'long long unsigned int'} [-Werror=format=]
pr_debug4("%s pos:%#zx ip:%#lx P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
/git/linux/tools/perf/util/debug.h:35:29: note: in expansion of macro 'pr_debugN'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
/git/linux/tools/perf/util/debug.h:35:42: note: in expansion of macro 'pr_fmt'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
util/s390-cpumsf.c:421:2: note: in expansion of macro 'pr_debug4'
pr_debug4("%s pos:%#zx ip:%#lx P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
^~~~~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_samples':
util/s390-cpumsf.c:501:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'off_t' {aka 'long long int'} [-Werror=format=]
pr_err("[%#08lx] Invalid AUX trailer entry TOD clock base\n",
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
util/s390-cpumsf.c:501:3: note: in expansion of macro 'pr_err'
pr_err("[%#08lx] Invalid AUX trailer entry TOD clock base\n",
^~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_run_decoder':
util/s390-cpumsf.c:610:12: error: format '%ld' expects argument of type 'long int', but argument 6 has type 'u64' {aka 'long long unsigned int'} [-Werror=format=]
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
/git/linux/tools/perf/util/debug.h:35:29: note: in expansion of macro 'pr_debugN'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
/git/linux/tools/perf/util/debug.h:35:42: note: in expansion of macro 'pr_fmt'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
util/s390-cpumsf.c:610:2: note: in expansion of macro 'pr_debug4'
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^~~~~~~~~
util/s390-cpumsf.c:610:12: error: format '%lx' expects argument of type 'long unsigned int', but argument 7 has type 'u64' {aka 'long long unsigned int'} [-Werror=format=]
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
/git/linux/tools/perf/util/debug.h:35:29: note: in expansion of macro 'pr_debugN'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
/git/linux/tools/perf/util/debug.h:35:42: note: in expansion of macro 'pr_fmt'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
util/s390-cpumsf.c:610:2: note: in expansion of macro 'pr_debug4'
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^~~~~~~~~
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
26 17.49 fedora:24-x-ARC-uClibc : FAIL arc-linux-gcc (ARCompact ISA Linux uClibc toolchain 2017.09-rc2) 7.1.1 20170710
-----------------------------------------------------------------------------------
CC /tmp/build/perf/util/s390-cpumsf.o
CC /tmp/build/perf/util/parse-branch-options.o
In file included from util/s390-cpumsf.c:161:0:
util/s390-cpumsf-kernel.h:16:15: error: packed attribute causes inefficient alignment for 'def' [-Werror=attributes]
unsigned int def:16; /* 0-15 Data Entry Format */
^~~
util/s390-cpumsf-kernel.h:25:15: error: packed attribute causes inefficient alignment for 'CL' [-Werror=attributes]
unsigned int CL:2; /* 32-33 Configuration Level */
^~
util/s390-cpumsf-kernel.h:28:21: error: packed attribute causes inefficient alignment for 'ia' [-Werror=attributes]
unsigned long long ia; /* Instruction Address */
^~
util/s390-cpumsf-kernel.h:29:21: error: packed attribute causes inefficient alignment for 'gpp' [-Werror=attributes]
unsigned long long gpp; /* Guest Program Parameter */
^~~
util/s390-cpumsf-kernel.h:30:21: error: packed attribute causes inefficient alignment for 'hpp' [-Werror=attributes]
unsigned long long hpp; /* Host Program Parameter */
^~~
util/s390-cpumsf-kernel.h:34:15: error: packed attribute causes inefficient alignment for 'def' [-Werror=attributes]
unsigned int def:16; /* 0-15 Data Entry Format */
^~~
In file included from util/cpumap.h:10:0,
from util/s390-cpumsf.c:150:
util/s390-cpumsf.c: In function 's390_cpumsf_diag_show':
util/s390-cpumsf.c:208:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t {aka unsigned int}' [-Werror=format=]
pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
^
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
util/s390-cpumsf.c:208:3: note: in expansion of macro 'pr_err'
pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
^~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_trailer_show':
util/s390-cpumsf.c:233:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t {aka unsigned int}' [-Werror=format=]
pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
^
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
util/s390-cpumsf.c:233:3: note: in expansion of macro 'pr_err'
pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
^~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_make_event':
util/s390-cpumsf.c:421:12: error: format '%lx' expects argument of type 'long unsigned int', but argument 6 has type 'u64 {aka long long unsigned int}' [-Werror=format=]
pr_debug4("%s pos:%#zx ip:%#lx P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
^
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
/git/linux/tools/perf/util/debug.h:35:29: note: in expansion of macro 'pr_debugN'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
/git/linux/tools/perf/util/debug.h:35:42: note: in expansion of macro 'pr_fmt'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
util/s390-cpumsf.c:421:2: note: in expansion of macro 'pr_debug4'
pr_debug4("%s pos:%#zx ip:%#lx P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
^~~~~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_samples':
util/s390-cpumsf.c:501:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'off_t {aka long long int}' [-Werror=format=]
pr_err("[%#08lx] Invalid AUX trailer entry TOD clock base\n",
^
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
util/s390-cpumsf.c:501:3: note: in expansion of macro 'pr_err'
pr_err("[%#08lx] Invalid AUX trailer entry TOD clock base\n",
^~~~~~
util/s390-cpumsf.c: In function 's390_cpumsf_run_decoder':
util/s390-cpumsf.c:610:12: error: format '%ld' expects argument of type 'long int', but argument 6 has type 'u64 {aka long long unsigned int}' [-Werror=format=]
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
/git/linux/tools/perf/util/debug.h:35:29: note: in expansion of macro 'pr_debugN'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
/git/linux/tools/perf/util/debug.h:35:42: note: in expansion of macro 'pr_fmt'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
util/s390-cpumsf.c:610:2: note: in expansion of macro 'pr_debug4'
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^~~~~~~~~
util/s390-cpumsf.c:610:12: error: format '%lx' expects argument of type 'long unsigned int', but argument 7 has type 'u64 {aka long long unsigned int}' [-Werror=format=]
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^
/git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
#define pr_fmt(fmt) fmt
^~~
/git/linux/tools/perf/util/debug.h:35:29: note: in expansion of macro 'pr_debugN'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~~~~
/git/linux/tools/perf/util/debug.h:35:42: note: in expansion of macro 'pr_fmt'
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
^~~~~~
util/s390-cpumsf.c:610:2: note: in expansion of macro 'pr_debug4'
pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
^~~~~~~~~
CC /tmp/build/perf/util/dump-insn.o
CC /tmp/build/perf/util/parse-regs-options.o
CC /tmp/build/perf/util/term.o
CC /tmp/build/perf/util/help-unknown-cmd.o
CC /tmp/build/perf/util/mem-events.o
cc1: all warnings being treated as errors
mv: cannot stat '/tmp/build/perf/util/.s390-cpumsf.o.tmp': No such file or directory
/git/linux/tools/build/Makefile.build:96: recipe for target '/tmp/build/perf/util/s390-cpumsf.o' failed
make[4]: *** [/tmp/build/perf/util/s390-cpumsf.o] Error 1
make[4]: *** Waiting for unfinished jobs....
CC /tmp/build/perf/util/intel-pt-decoder/intel-pt-insn-decoder.o
LD /tmp/build/perf/util/intel-pt-decoder/libperf-in.o
/git/linux/tools/build/Makefile.build:139: recipe for target 'util' failed
make[3]: *** [util] Error 2
Makefile.perf:633: recipe for target '/tmp/build/perf/libperf-in.o' failed
make[2]: *** [/tmp/build/perf/libperf-in.o] Error 2
Makefile.perf:205: recipe for target 'sub-make' failed
make[1]: *** [sub-make] Error 2
Makefile:69: recipe for target 'all' failed
make: *** [all] Error 2
make: Leaving directory '/git/linux/tools/perf'
[root@seventh ~]#
Em Wed, Aug 08, 2018 at 01:14:51PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Wed, Aug 08, 2018 at 01:08:43PM -0300, Arnaldo Carvalho de Melo escreveu:
> > No need for __packed.
>
> > I'm removing that to avoid having this failling in compilers that have
> > such a warning, since we default to Werror.
>
> > Holler if there is something I'missing :-)
>
> In file included from util/cpumap.h:10,
> from util/s390-cpumsf.c:150:
> util/s390-cpumsf.c: In function 's390_cpumsf_diag_show':
> util/s390-cpumsf.c:208:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Werror=format=]
> pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
> #define pr_fmt(fmt) fmt
> ^~~
> util/s390-cpumsf.c:208:3: note: in expansion of macro 'pr_err'
> pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
> ^~~~~~
> util/s390-cpumsf.c: In function 's390_cpumsf_trailer_show':
> util/s390-cpumsf.c:233:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Werror=format=]
> pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
So for those I applied this, seems to pass the ones that were failing,
restarting tests...
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index 2bcb160a08f0..d2c78ffd9fee 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -187,7 +187,7 @@ static bool s390_cpumsf_basic_show(const char *color, size_t pos,
pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos);
return false;
}
- color_fprintf(stdout, color, " [%#08x] Basic Def:%04x Inst:%#04x"
+ color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x"
" %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n"
"\t\tCL:%d HPP:%#018llx GPP:%#018llx\n",
pos, basic->def, basic->U,
@@ -205,10 +205,10 @@ static bool s390_cpumsf_diag_show(const char *color, size_t pos,
struct hws_diag_entry *diag)
{
if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) {
- pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
+ pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos);
return false;
}
- color_fprintf(stdout, color, " [%#08x] Diag Def:%04x %c\n",
+ color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n",
pos, diag->def, diag->I ? 'I' : ' ');
return true;
}
@@ -230,10 +230,10 @@ static bool s390_cpumsf_trailer_show(const char *color, size_t pos,
struct hws_trailer_entry *te)
{
if (te->bsdes != sizeof(struct hws_basic_entry)) {
- pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
+ pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos);
return false;
}
- color_fprintf(stdout, color, " [%#08x] Trailer %c%c%c bsdes:%d"
+ color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d"
" dsdes:%d Overflow:%lld Time:%#llx\n"
"\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n",
pos,
@@ -418,7 +418,7 @@ static bool s390_cpumsf_make_event(size_t pos,
event.sample.header.misc = sample.cpumode;
event.sample.header.size = sizeof(struct perf_event_header);
- pr_debug4("%s pos:%#zx ip:%#lx P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
+ pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
__func__, pos, sample.ip, basic->P, basic->CL, sample.pid,
sample.tid, sample.cpumode, sample.cpu);
if (perf_session__deliver_synth_event(sfq->sf->session, &event,
@@ -498,7 +498,7 @@ static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts)
*/
aux_ts = get_trailer_time(buf);
if (!aux_ts) {
- pr_err("[%#08lx] Invalid AUX trailer entry TOD clock base\n",
+ pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n",
sfq->buffer->data_offset);
aux_ts = ~0ULL;
goto out;
@@ -607,7 +607,7 @@ static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
buffer->use_size = buffer->size;
buffer->use_data = buffer->data;
}
- pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
+ pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n",
__func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset,
buffer->size, buffer->use_size);
err = s390_cpumsf_samples(sfq, ts);
On 08/08/2018 06:42 PM, Arnaldo Carvalho de Melo wrote:
> Em Wed, Aug 08, 2018 at 01:14:51PM -0300, Arnaldo Carvalho de Melo escreveu:
>> Em Wed, Aug 08, 2018 at 01:08:43PM -0300, Arnaldo Carvalho de Melo escreveu:
>>> No need for __packed.
>>
>>> I'm removing that to avoid having this failling in compilers that have
>>> such a warning, since we default to Werror.
>>
>>> Holler if there is something I'missing :-)
>>
>> In file included from util/cpumap.h:10,
>> from util/s390-cpumsf.c:150:
>> util/s390-cpumsf.c: In function 's390_cpumsf_diag_show':
>> util/s390-cpumsf.c:208:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Werror=format=]
>> pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
>> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> /git/linux/tools/perf/util/debug.h:20:21: note: in definition of macro 'pr_fmt'
>> #define pr_fmt(fmt) fmt
>> ^~~
>> util/s390-cpumsf.c:208:3: note: in expansion of macro 'pr_err'
>> pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
>> ^~~~~~
>> util/s390-cpumsf.c: In function 's390_cpumsf_trailer_show':
>> util/s390-cpumsf.c:233:10: error: format '%lx' expects argument of type 'long unsigned int', but argument 4 has type 'size_t' {aka 'unsigned int'} [-Werror=format=]
>> pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
>
> So for those I applied this, seems to pass the ones that were failing,
> restarting tests...
>
> diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
> index 2bcb160a08f0..d2c78ffd9fee 100644
> --- a/tools/perf/util/s390-cpumsf.c
> +++ b/tools/perf/util/s390-cpumsf.c
> @@ -187,7 +187,7 @@ static bool s390_cpumsf_basic_show(const char *color, size_t pos,
> pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos);
> return false;
> }
> - color_fprintf(stdout, color, " [%#08x] Basic Def:%04x Inst:%#04x"
> + color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x"
> " %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n"
> "\t\tCL:%d HPP:%#018llx GPP:%#018llx\n",
> pos, basic->def, basic->U,
> @@ -205,10 +205,10 @@ static bool s390_cpumsf_diag_show(const char *color, size_t pos,
> struct hws_diag_entry *diag)
> {
> if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) {
> - pr_err("Invalid AUX trace diagnostic entry [%#08lx]\n", pos);
> + pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos);
> return false;
> }
> - color_fprintf(stdout, color, " [%#08x] Diag Def:%04x %c\n",
> + color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n",
> pos, diag->def, diag->I ? 'I' : ' ');
> return true;
> }
> @@ -230,10 +230,10 @@ static bool s390_cpumsf_trailer_show(const char *color, size_t pos,
> struct hws_trailer_entry *te)
> {
> if (te->bsdes != sizeof(struct hws_basic_entry)) {
> - pr_err("Invalid AUX trace trailer entry [%#08lx]\n", pos);
> + pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos);
> return false;
> }
> - color_fprintf(stdout, color, " [%#08x] Trailer %c%c%c bsdes:%d"
> + color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d"
> " dsdes:%d Overflow:%lld Time:%#llx\n"
> "\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n",
> pos,
> @@ -418,7 +418,7 @@ static bool s390_cpumsf_make_event(size_t pos,
> event.sample.header.misc = sample.cpumode;
> event.sample.header.size = sizeof(struct perf_event_header);
>
> - pr_debug4("%s pos:%#zx ip:%#lx P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
> + pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
> __func__, pos, sample.ip, basic->P, basic->CL, sample.pid,
> sample.tid, sample.cpumode, sample.cpu);
> if (perf_session__deliver_synth_event(sfq->sf->session, &event,
> @@ -498,7 +498,7 @@ static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts)
> */
> aux_ts = get_trailer_time(buf);
> if (!aux_ts) {
> - pr_err("[%#08lx] Invalid AUX trailer entry TOD clock base\n",
> + pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n",
> sfq->buffer->data_offset);
> aux_ts = ~0ULL;
> goto out;
> @@ -607,7 +607,7 @@ static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
> buffer->use_size = buffer->size;
> buffer->use_data = buffer->data;
> }
> - pr_debug4("%s queue_nr:%d buffer:%ld offset:%#lx size:%#zx rest:%#zx\n",
> + pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n",
> __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset,
> buffer->size, buffer->use_size);
> err = s390_cpumsf_samples(sfq, ts);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-perf-users" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
I just updated the perf/core branch, compiled it and all works fine.
Thanks for fixing these errors.
--
Thomas Richter, Dept 3303, IBM s390 Linux Development, Boeblingen, Germany
--
Vorsitzende des Aufsichtsrats: Martina Koederitz
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen / Registergericht: Amtsgericht Stuttgart, HRB 243294
Em Thu, Aug 09, 2018 at 06:35:58AM +0200, Thomas-Mich Richter escreveu:
> On 08/08/2018 06:42 PM, Arnaldo Carvalho de Melo wrote:
> > So for those I applied this, seems to pass the ones that were failing,
> > restarting tests...
> I just updated the perf/core branch, compiled it and all works fine.
Thanks for checking!
> Thanks for fixing these errors.
You're welcome,
- Arnaldo
Arnaldo Carvalho de Melo <[email protected]> writes:
> Em Thu, Aug 09, 2018 at 06:35:58AM +0200, Thomas-Mich Richter escreveu:
>> On 08/08/2018 06:42 PM, Arnaldo Carvalho de Melo wrote:
>> > So for those I applied this, seems to pass the ones that were failing,
>> > restarting tests...
>
>> I just updated the perf/core branch, compiled it and all works fine.
>
> Thanks for checking!
Yep all building OK here too.
Thanks all.
cheers
Commit-ID: b96e6615cd197022017808a9fe82f1737e307875
Gitweb: https://git.kernel.org/tip/b96e6615cd197022017808a9fe82f1737e307875
Author: Thomas Richter <[email protected]>
AuthorDate: Thu, 2 Aug 2018 09:46:20 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 3 Aug 2018 10:34:18 -0300
perf auxtrace: Support for perf report -D for s390
Add initial support for s390 auxiliary traces using the CPU-Measurement
Sampling Facility.
Support and ignore PERF_REPORT_AUXTRACE_INFO records in the perf data
file. Later patches will show the contents of the auxiliary traces.
Setup the auxtrace queues and data structures for s390. A raw dump of
the perf.data file now does not show an error when an auxtrace event is
encountered.
Output before:
[root@s35lp76 perf]# ./perf report -D -i perf.data.auxtrace
0x128 [0x10]: failed to process type: 70
Error:
failed to process sample
0x128 [0x10]: event: 70
.
. ... raw event: size 16 bytes
. 0000: 00 00 00 46 00 00 00 10 00 00 00 00 00 00 00 00 ...F............
0x128 [0x10]: PERF_RECORD_AUXTRACE_INFO type: 0
[root@s35lp76 perf]#
Output after:
# ./perf report -D -i perf.data.auxtrace |fgrep PERF_RECORD_AUXTRACE
0 0 0x128 [0x10]: PERF_RECORD_AUXTRACE_INFO type: 5
0 0 0x25a66 [0x30]: PERF_RECORD_AUXTRACE size: 0x40000
offset: 0 ref: 0 idx: 4 tid: -1 cpu: 4
....
Additional notes about the underlying hardware and software
implementation, provided by Hendrik Brueckner (see Link: below).
=============================================================================
The CPU-Measurement Facility (CPU-MF) provides a set of functions to obtain
performance information on the mainframe. Basically, it was introduced
with System z10 years ago for the z/Architecture, that means, 64-bit.
For Linux, there are two facilities of interest, counter facility and sampling
facility. The counter facility provides hardware counters for instructions,
cycles, crypto-activities, and many more.
The sampling facility is a hardware sampler that when started will write
samples at a particular interval into a sampling buffer. At some point,
for example, if a sample block is full, it generates an interrupt to collect
samples (while the sampler continues to run).
Few years ago, I started to provide the a perf PMU to use the counter
and sampling facilities. Recently, the device driver was updated to also
"export" the sampling buffer into the AUX area. Thomas now completed the
related perf work to interpret and process these AUX data.
If people are more interested in the sampling facility, they can have a
look into:
- The Load-Program-Parameter and the CPU-Measurement Facilities, SA23-2260-05
http://www-01.ibm.com/support/docview.wss?uid=isg26fcd1cc32246f4c8852574ce0044734a
and to learn how-to use it for Linux on Z, have look at chapter 54,
"Using the CPU-measurement facilities" in the:
- Device Drivers, Features, and Commands, SC33-8411-34
http://public.dhe.ibm.com/software/dw/linux390/docu/l416dd34.pdf
=============================================================================
Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Cc: Heiko Carstens <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/arch/s390/util/auxtrace.c | 1 +
tools/perf/util/Build | 1 +
tools/perf/util/auxtrace.c | 3 +
tools/perf/util/auxtrace.h | 1 +
tools/perf/util/s390-cpumsf.c | 123 +++++++++++++++++++++++++++++++++++
tools/perf/util/s390-cpumsf.h | 21 ++++++
6 files changed, 150 insertions(+)
diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c
index 3afe8256eff2..44c857388897 100644
--- a/tools/perf/arch/s390/util/auxtrace.c
+++ b/tools/perf/arch/s390/util/auxtrace.c
@@ -30,6 +30,7 @@ cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused,
struct auxtrace_info_event *auxtrace_info __maybe_unused,
size_t priv_size __maybe_unused)
{
+ auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF;
return 0;
}
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index b604ef334dc9..7efe15b9618d 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
libperf-$(CONFIG_AUXTRACE) += intel-bts.o
libperf-$(CONFIG_AUXTRACE) += arm-spe.o
libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
+libperf-$(CONFIG_AUXTRACE) += s390-cpumsf.o
ifdef CONFIG_LIBOPENCSD
libperf-$(CONFIG_AUXTRACE) += cs-etm.o
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index d056447520a2..ae8c37b219c9 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -56,6 +56,7 @@
#include "intel-pt.h"
#include "intel-bts.h"
#include "arm-spe.h"
+#include "s390-cpumsf.h"
#include "sane_ctype.h"
#include "symbol/kallsyms.h"
@@ -920,6 +921,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
return arm_spe_process_auxtrace_info(event, session);
case PERF_AUXTRACE_CS_ETM:
return cs_etm__process_auxtrace_info(event, session);
+ case PERF_AUXTRACE_S390_CPUMSF:
+ return s390_cpumsf_process_auxtrace_info(event, session);
case PERF_AUXTRACE_UNKNOWN:
default:
return -EINVAL;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index e731f55da072..71fc3bd74299 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -44,6 +44,7 @@ enum auxtrace_type {
PERF_AUXTRACE_INTEL_BTS,
PERF_AUXTRACE_CS_ETM,
PERF_AUXTRACE_ARM_SPE,
+ PERF_AUXTRACE_S390_CPUMSF,
};
enum itrace_period_type {
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
new file mode 100644
index 000000000000..e9a5ea21dbbf
--- /dev/null
+++ b/tools/perf/util/s390-cpumsf.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2018
+ * Auxtrace support for s390 CPU-Measurement Sampling Facility
+ *
+ * Author(s): Thomas Richter <[email protected]>
+ */
+
+#include <endian.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <inttypes.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+
+#include "cpumap.h"
+#include "color.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "machine.h"
+#include "session.h"
+#include "util.h"
+#include "thread.h"
+#include "debug.h"
+#include "auxtrace.h"
+#include "s390-cpumsf.h"
+
+struct s390_cpumsf {
+ struct auxtrace auxtrace;
+ struct auxtrace_queues queues;
+ struct auxtrace_heap heap;
+ struct perf_session *session;
+ struct machine *machine;
+ u32 auxtrace_type;
+ u32 pmu_type;
+};
+
+static int
+s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_sample *sample __maybe_unused,
+ struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+static int
+s390_cpumsf_process_auxtrace_event(struct perf_session *session __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+static int s390_cpumsf_flush(struct perf_session *session __maybe_unused,
+ struct perf_tool *tool __maybe_unused)
+{
+ return 0;
+}
+
+static void s390_cpumsf_free_events(struct perf_session *session)
+{
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+ struct auxtrace_queues *queues = &sf->queues;
+ unsigned int i;
+
+ for (i = 0; i < queues->nr_queues; i++)
+ zfree(&queues->queue_array[i].priv);
+ auxtrace_queues__free(queues);
+}
+
+static void s390_cpumsf_free(struct perf_session *session)
+{
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+
+ auxtrace_heap__free(&sf->heap);
+ s390_cpumsf_free_events(session);
+ session->auxtrace = NULL;
+ free(sf);
+}
+
+int s390_cpumsf_process_auxtrace_info(union perf_event *event,
+ struct perf_session *session)
+{
+ struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
+ struct s390_cpumsf *sf;
+ int err;
+
+ if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event))
+ return -EINVAL;
+
+ sf = zalloc(sizeof(struct s390_cpumsf));
+ if (sf == NULL)
+ return -ENOMEM;
+
+ err = auxtrace_queues__init(&sf->queues);
+ if (err)
+ goto err_free;
+
+ sf->session = session;
+ sf->machine = &session->machines.host; /* No kvm support */
+ sf->auxtrace_type = auxtrace_info->type;
+ sf->pmu_type = PERF_TYPE_RAW;
+
+ sf->auxtrace.process_event = s390_cpumsf_process_event;
+ sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event;
+ sf->auxtrace.flush_events = s390_cpumsf_flush;
+ sf->auxtrace.free_events = s390_cpumsf_free_events;
+ sf->auxtrace.free = s390_cpumsf_free;
+ session->auxtrace = &sf->auxtrace;
+
+ return 0;
+
+err_free:
+ free(sf);
+ return err;
+}
diff --git a/tools/perf/util/s390-cpumsf.h b/tools/perf/util/s390-cpumsf.h
new file mode 100644
index 000000000000..fb64d100555c
--- /dev/null
+++ b/tools/perf/util/s390-cpumsf.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright IBM Corp. 2018
+ * Auxtrace support for s390 CPU-Measurement Sampling Facility
+ *
+ * Author(s): Thomas Richter <[email protected]>
+ */
+
+#ifndef INCLUDE__PERF_S390_CPUMSF_H
+#define INCLUDE__PERF_S390_CPUMSF_H
+
+union perf_event;
+struct perf_session;
+struct perf_pmu;
+
+struct auxtrace_record *
+s390_cpumsf_recording_init(int *err, struct perf_pmu *s390_cpumsf_pmu);
+
+int s390_cpumsf_process_auxtrace_info(union perf_event *event,
+ struct perf_session *session);
+#endif
Commit-ID: 2b1444f2e28be94b8f0b37376e1c619fd8cad63b
Gitweb: https://git.kernel.org/tip/2b1444f2e28be94b8f0b37376e1c619fd8cad63b
Author: Thomas Richter <[email protected]>
AuthorDate: Thu, 2 Aug 2018 09:46:21 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 8 Aug 2018 15:26:48 -0300
perf report: Add raw report support for s390 auxiliary trace
Add support for s390 auxiliary trace support.
Use 'perf record -e rbd000' to create the perf.data file. The event
also has the symbolic name SF_CYCLES_BASIC_DIAG, using 'perf record -e
SF_CYCLES_BASIC_DIAG' is equivalent.
Use 'perf report -D' to display the auxiliary trace data.
Output before:
0 0 0x25a66 [0x30]: PERF_RECORD_AUXTRACE size: 0x40000
offset: 0 ref: 0 idx: 4 tid: -1 cpu: 4
Nothing else
Output after:
0 0 0x25a66 [0x30]: PERF_RECORD_AUXTRACE size: 0x40000
offset: 0 ref: 0 idx: 4 tid: -1 cpu: 4
.
. ... s390 AUX data: size 262144 bytes
[00000000] Basic Def:0001 Inst:0000 TW AS:3 ASN:0xffff IA:0x0000000000c2f1bc
CL:1 HPP:0x8000000000000000 GPP:000000000000000000
[0x000020] Diag Def:8005
[0x0000bf] Basic Def:0001 Inst:0000 TW AS:3 ASN:0xffff IA:0x0000000000c2f1bc
CL:1 HPP:0x8000000000000000 GPP:000000000000000000
[0x0000df] Diag Def:8005
[0x00017e] Basic Def:0001 Inst:0000 TW AS:3 ASN:0xffff IA:0x0000000000c2f1bc
CL:1 HPP:0x8000000000000000 GPP:000000000000000000
....
[0x000fc0] Trailer F T bsdes:32 dsdes:159 Overflow:0 Time:0xd4ab59a8450fa108
C:1 TOD:0xd4ab4ec98ceb3832 1:0x8000000000000000 2:0xd4ab4ec98ceb3832
This output is shown for every sampled data block. The
output contains the
- basic-sampling data entry
- diagnostic-sampling data entry
- trailer entry
The basic sampling entry and diagnostic sampling entry sizes can be
extracted using the trailer entries in the SDB. On older hardware these
values (bsdes and dsdes in the trailer entry) are reserved and zero.
Older hardware use hard coded values based on the s390 machine type.
Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Michael Ellerman <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Link: http://lkml.kernel.org/r/[email protected]
[ Merged a fix for a 'tipe puned' problem reported by Michael Ellerman see last Link tag. ]
[ Removed __packed from two structs, they're already naturally packed and having that. ]
[ attribute breaks the build in gcc 8.1.1 mips, 4.4.7 x86_64, 7.1.1 ARCompact ISA, etc) ]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/s390-cpumsf-kernel.h | 71 ++++++++++
tools/perf/util/s390-cpumsf.c | 247 ++++++++++++++++++++++++++++++++++-
2 files changed, 317 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/s390-cpumsf-kernel.h b/tools/perf/util/s390-cpumsf-kernel.h
new file mode 100644
index 000000000000..de8c7ad0eca8
--- /dev/null
+++ b/tools/perf/util/s390-cpumsf-kernel.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Auxtrace support for s390 CPU measurement sampling facility
+ *
+ * Copyright IBM Corp. 2018
+ * Author(s): Hendrik Brueckner <[email protected]>
+ * Thomas Richter <[email protected]>
+ */
+#ifndef S390_CPUMSF_KERNEL_H
+#define S390_CPUMSF_KERNEL_H
+
+#define S390_CPUMSF_PAGESZ 4096 /* Size of sample block units */
+#define S390_CPUMSF_DIAG_DEF_FIRST 0x8001 /* Diagnostic entry lowest id */
+
+struct hws_basic_entry {
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int R:4; /* 16-19 reserved */
+ unsigned int U:4; /* 20-23 Number of unique instruct. */
+ unsigned int z:2; /* zeros */
+ unsigned int T:1; /* 26 PSW DAT mode */
+ unsigned int W:1; /* 27 PSW wait state */
+ unsigned int P:1; /* 28 PSW Problem state */
+ unsigned int AS:2; /* 29-30 PSW address-space control */
+ unsigned int I:1; /* 31 entry valid or invalid */
+ unsigned int CL:2; /* 32-33 Configuration Level */
+ unsigned int:14;
+ unsigned int prim_asn:16; /* primary ASN */
+ unsigned long long ia; /* Instruction Address */
+ unsigned long long gpp; /* Guest Program Parameter */
+ unsigned long long hpp; /* Host Program Parameter */
+};
+
+struct hws_diag_entry {
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int R:15; /* 16-19 and 20-30 reserved */
+ unsigned int I:1; /* 31 entry valid or invalid */
+ u8 data[]; /* Machine-dependent sample data */
+};
+
+struct hws_combined_entry {
+ struct hws_basic_entry basic; /* Basic-sampling data entry */
+ struct hws_diag_entry diag; /* Diagnostic-sampling data entry */
+};
+
+struct hws_trailer_entry {
+ union {
+ struct {
+ unsigned int f:1; /* 0 - Block Full Indicator */
+ unsigned int a:1; /* 1 - Alert request control */
+ unsigned int t:1; /* 2 - Timestamp format */
+ unsigned int:29; /* 3 - 31: Reserved */
+ unsigned int bsdes:16; /* 32-47: size of basic SDE */
+ unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */
+ };
+ unsigned long long flags; /* 0 - 64: All indicators */
+ };
+ unsigned long long overflow; /* 64 - sample Overflow count */
+ unsigned char timestamp[16]; /* 16 - 31 timestamp */
+ unsigned long long reserved1; /* 32 -Reserved */
+ unsigned long long reserved2; /* */
+ union { /* 48 - reserved for programming use */
+ struct {
+ unsigned long long clock_base:1; /* in progusage2 */
+ unsigned long long progusage1:63;
+ unsigned long long progusage2;
+ };
+ unsigned long long progusage[2];
+ };
+};
+
+#endif
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index e9a5ea21dbbf..14728b0834c6 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -26,6 +26,7 @@
#include "debug.h"
#include "auxtrace.h"
#include "s390-cpumsf.h"
+#include "s390-cpumsf-kernel.h"
struct s390_cpumsf {
struct auxtrace auxtrace;
@@ -35,8 +36,213 @@ struct s390_cpumsf {
struct machine *machine;
u32 auxtrace_type;
u32 pmu_type;
+ u16 machine_type;
};
+/* Display s390 CPU measurement facility basic-sampling data entry */
+static bool s390_cpumsf_basic_show(const char *color, size_t pos,
+ struct hws_basic_entry *basic)
+{
+ if (basic->def != 1) {
+ pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos);
+ return false;
+ }
+ color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x"
+ " %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n"
+ "\t\tCL:%d HPP:%#018llx GPP:%#018llx\n",
+ pos, basic->def, basic->U,
+ basic->T ? 'T' : ' ',
+ basic->W ? 'W' : ' ',
+ basic->P ? 'P' : ' ',
+ basic->I ? 'I' : ' ',
+ basic->AS, basic->prim_asn, basic->ia, basic->CL,
+ basic->hpp, basic->gpp);
+ return true;
+}
+
+/* Display s390 CPU measurement facility diagnostic-sampling data entry */
+static bool s390_cpumsf_diag_show(const char *color, size_t pos,
+ struct hws_diag_entry *diag)
+{
+ if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) {
+ pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos);
+ return false;
+ }
+ color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n",
+ pos, diag->def, diag->I ? 'I' : ' ');
+ return true;
+}
+
+/* Return TOD timestamp contained in an trailer entry */
+static unsigned long long trailer_timestamp(struct hws_trailer_entry *te)
+{
+ /* te->t set: TOD in STCKE format, bytes 8-15
+ * to->t not set: TOD in STCK format, bytes 0-7
+ */
+ unsigned long long ts;
+
+ memcpy(&ts, &te->timestamp[te->t], sizeof(ts));
+ return ts;
+}
+
+/* Display s390 CPU measurement facility trailer entry */
+static bool s390_cpumsf_trailer_show(const char *color, size_t pos,
+ struct hws_trailer_entry *te)
+{
+ if (te->bsdes != sizeof(struct hws_basic_entry)) {
+ pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos);
+ return false;
+ }
+ color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d"
+ " dsdes:%d Overflow:%lld Time:%#llx\n"
+ "\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n",
+ pos,
+ te->f ? 'F' : ' ',
+ te->a ? 'A' : ' ',
+ te->t ? 'T' : ' ',
+ te->bsdes, te->dsdes, te->overflow,
+ trailer_timestamp(te), te->clock_base, te->progusage2,
+ te->progusage[0], te->progusage[1]);
+ return true;
+}
+
+/* Test a sample data block. It must be 4KB or a multiple thereof in size and
+ * 4KB page aligned. Each sample data page has a trailer entry at the
+ * end which contains the sample entry data sizes.
+ *
+ * Return true if the sample data block passes the checks and set the
+ * basic set entry size and diagnostic set entry size.
+ *
+ * Return false on failure.
+ *
+ * Note: Old hardware does not set the basic or diagnostic entry sizes
+ * in the trailer entry. Use the type number instead.
+ */
+static bool s390_cpumsf_validate(int machine_type,
+ unsigned char *buf, size_t len,
+ unsigned short *bsdes,
+ unsigned short *dsdes)
+{
+ struct hws_basic_entry *basic = (struct hws_basic_entry *)buf;
+ struct hws_trailer_entry *te;
+
+ *dsdes = *bsdes = 0;
+ if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */
+ return false;
+ if (basic->def != 1) /* No basic set entry, must be first */
+ return false;
+ /* Check for trailer entry at end of SDB */
+ te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
+ - sizeof(*te));
+ *bsdes = te->bsdes;
+ *dsdes = te->dsdes;
+ if (!te->bsdes && !te->dsdes) {
+ /* Very old hardware, use CPUID */
+ switch (machine_type) {
+ case 2097:
+ case 2098:
+ *dsdes = 64;
+ *bsdes = 32;
+ break;
+ case 2817:
+ case 2818:
+ *dsdes = 74;
+ *bsdes = 32;
+ break;
+ case 2827:
+ case 2828:
+ *dsdes = 85;
+ *bsdes = 32;
+ break;
+ default:
+ /* Illegal trailer entry */
+ return false;
+ }
+ }
+ return true;
+}
+
+/* Return true if there is room for another entry */
+static bool s390_cpumsf_reached_trailer(size_t entry_sz, size_t pos)
+{
+ size_t payload = S390_CPUMSF_PAGESZ - sizeof(struct hws_trailer_entry);
+
+ if (payload - (pos & (S390_CPUMSF_PAGESZ - 1)) < entry_sz)
+ return false;
+ return true;
+}
+
+/* Dump an auxiliary buffer. These buffers are multiple of
+ * 4KB SDB pages.
+ */
+static void s390_cpumsf_dump(struct s390_cpumsf *sf,
+ unsigned char *buf, size_t len)
+{
+ const char *color = PERF_COLOR_BLUE;
+ struct hws_basic_entry *basic;
+ struct hws_diag_entry *diag;
+ size_t pos = 0;
+ unsigned short bsdes, dsdes;
+
+ color_fprintf(stdout, color,
+ ". ... s390 AUX data: size %zu bytes\n",
+ len);
+
+ if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
+ &dsdes)) {
+ pr_err("Invalid AUX trace data block size:%zu"
+ " (type:%d bsdes:%hd dsdes:%hd)\n",
+ len, sf->machine_type, bsdes, dsdes);
+ return;
+ }
+
+ /* s390 kernel always returns 4KB blocks fully occupied,
+ * no partially filled SDBs.
+ */
+ while (pos < len) {
+ /* Handle Basic entry */
+ basic = (struct hws_basic_entry *)(buf + pos);
+ if (s390_cpumsf_basic_show(color, pos, basic))
+ pos += bsdes;
+ else
+ return;
+
+ /* Handle Diagnostic entry */
+ diag = (struct hws_diag_entry *)(buf + pos);
+ if (s390_cpumsf_diag_show(color, pos, diag))
+ pos += dsdes;
+ else
+ return;
+
+ /* Check for trailer entry */
+ if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
+ /* Show trailer entry */
+ struct hws_trailer_entry te;
+
+ pos = (pos + S390_CPUMSF_PAGESZ)
+ & ~(S390_CPUMSF_PAGESZ - 1);
+ pos -= sizeof(te);
+ memcpy(&te, buf + pos, sizeof(te));
+ /* Set descriptor sizes in case of old hardware
+ * where these values are not set.
+ */
+ te.bsdes = bsdes;
+ te.dsdes = dsdes;
+ if (s390_cpumsf_trailer_show(color, pos, &te))
+ pos += sizeof(te);
+ else
+ return;
+ }
+ }
+}
+
+static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf,
+ size_t len)
+{
+ printf(".\n");
+ s390_cpumsf_dump(sf, buf, len);
+}
+
static int
s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
union perf_event *event __maybe_unused,
@@ -47,10 +253,40 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
}
static int
-s390_cpumsf_process_auxtrace_event(struct perf_session *session __maybe_unused,
+s390_cpumsf_process_auxtrace_event(struct perf_session *session,
union perf_event *event __maybe_unused,
struct perf_tool *tool __maybe_unused)
{
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+
+ int fd = perf_data__fd(session->data);
+ struct auxtrace_buffer *buffer;
+ off_t data_offset;
+ int err;
+
+ if (perf_data__is_pipe(session->data)) {
+ data_offset = 0;
+ } else {
+ data_offset = lseek(fd, 0, SEEK_CUR);
+ if (data_offset == -1)
+ return -errno;
+ }
+
+ err = auxtrace_queues__add_event(&sf->queues, session, event,
+ data_offset, &buffer);
+ if (err)
+ return err;
+
+ /* Dump here after copying piped trace out of the pipe */
+ if (dump_trace) {
+ if (auxtrace_buffer__get_data(buffer, fd)) {
+ s390_cpumsf_dump_event(sf, buffer->data,
+ buffer->size);
+ auxtrace_buffer__put_data(buffer);
+ }
+ }
return 0;
}
@@ -85,6 +321,14 @@ static void s390_cpumsf_free(struct perf_session *session)
free(sf);
}
+static int s390_cpumsf_get_type(const char *cpuid)
+{
+ int ret, family = 0;
+
+ ret = sscanf(cpuid, "%*[^,],%u", &family);
+ return (ret == 1) ? family : 0;
+}
+
int s390_cpumsf_process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
@@ -107,6 +351,7 @@ int s390_cpumsf_process_auxtrace_info(union perf_event *event,
sf->machine = &session->machines.host; /* No kvm support */
sf->auxtrace_type = auxtrace_info->type;
sf->pmu_type = PERF_TYPE_RAW;
+ sf->machine_type = s390_cpumsf_get_type(session->evlist->env->cpuid);
sf->auxtrace.process_event = s390_cpumsf_process_event;
sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event;
Commit-ID: 33d9e1832e528ff61f481558882ee0f82e288440
Gitweb: https://git.kernel.org/tip/33d9e1832e528ff61f481558882ee0f82e288440
Author: Thomas Richter <[email protected]>
AuthorDate: Thu, 2 Aug 2018 09:46:22 +0200
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Wed, 8 Aug 2018 15:49:17 -0300
perf report: Add GUI report support for s390 auxiliary trace
Add support for s390 auxiliary trace support.
Use 'perf record -e rbd000 -- ls' to create the perf.data file.
Use 'perf report' to display the auxiliary trace data.
Output before:
[root@s35lp76 perf]# ./perf report --stdio
0x128 [0x10]: failed to process type: 70
Error:
failed to process sample
[root@s35lp76 perf]#
Output after:
[root@s35lp76 perf]# ./perf report --stdio
18.21% 18.21% ls [kernel.kallsyms] [k] ftrace_likely_update
9.52% 9.52% ls [kernel.kallsyms] [k] lock_acquire
9.38% 9.38% ls [kernel.kallsyms] [k] lock_release
3.45% 3.45% ls [kernel.kallsyms] [k] lock_acquired
2.88% 2.88% ls [kernel.kallsyms] [k] link_path_walk
2.63% 2.63% ls [kernel.kallsyms] [k] __d_lookup
2.38% 2.38% ls [kernel.kallsyms] [k] __d_lookup_rcu
2.04% 2.04% ls [kernel.kallsyms] [k] ___might_sleep
1.83% 1.83% ls [kernel.kallsyms] [k] debug_lockdep_rcu_enabled
1.44% 1.44% ls [kernel.kallsyms] [k] dput
....
Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Use PRI[xd]64 to fix the build on debian:experimental-x-mips (gcc 8.1.0) and others ]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/s390-cpumsf.c | 593 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 585 insertions(+), 8 deletions(-)
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index 14728b0834c6..d2c78ffd9fee 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -4,6 +4,138 @@
* Auxtrace support for s390 CPU-Measurement Sampling Facility
*
* Author(s): Thomas Richter <[email protected]>
+ *
+ * Auxiliary traces are collected during 'perf record' using rbd000 event.
+ * Several PERF_RECORD_XXX are generated during recording:
+ *
+ * PERF_RECORD_AUX:
+ * Records that new data landed in the AUX buffer part.
+ * PERF_RECORD_AUXTRACE:
+ * Defines auxtrace data. Followed by the actual data. The contents of
+ * the auxtrace data is dependent on the event and the CPU.
+ * This record is generated by perf record command. For details
+ * see Documentation/perf.data-file-format.txt.
+ * PERF_RECORD_AUXTRACE_INFO:
+ * Defines a table of contains for PERF_RECORD_AUXTRACE records. This
+ * record is generated during 'perf record' command. Each record contains up
+ * to 256 entries describing offset and size of the AUXTRACE data in the
+ * perf.data file.
+ * PERF_RECORD_AUXTRACE_ERROR:
+ * Indicates an error during AUXTRACE collection such as buffer overflow.
+ * PERF_RECORD_FINISHED_ROUND:
+ * Perf events are not necessarily in time stamp order, as they can be
+ * collected in parallel on different CPUs. If the events should be
+ * processed in time order they need to be sorted first.
+ * Perf report guarantees that there is no reordering over a
+ * PERF_RECORD_FINISHED_ROUND boundary event. All perf records with a
+ * time stamp lower than this record are processed (and displayed) before
+ * the succeeding perf record are processed.
+ *
+ * These records are evaluated during perf report command.
+ *
+ * 1. PERF_RECORD_AUXTRACE_INFO is used to set up the infrastructure for
+ * auxiliary trace data processing. See s390_cpumsf_process_auxtrace_info()
+ * below.
+ * Auxiliary trace data is collected per CPU. To merge the data into the report
+ * an auxtrace_queue is created for each CPU. It is assumed that the auxtrace
+ * data is in ascending order.
+ *
+ * Each queue has a double linked list of auxtrace_buffers. This list contains
+ * the offset and size of a CPU's auxtrace data. During auxtrace processing
+ * the data portion is mmap()'ed.
+ *
+ * To sort the queues in chronological order, all queue access is controlled
+ * by the auxtrace_heap. This is basicly a stack, each stack element has two
+ * entries, the queue number and a time stamp. However the stack is sorted by
+ * the time stamps. The highest time stamp is at the bottom the lowest
+ * (nearest) time stamp is at the top. That sort order is maintained at all
+ * times!
+ *
+ * After the auxtrace infrastructure has been setup, the auxtrace queues are
+ * filled with data (offset/size pairs) and the auxtrace_heap is populated.
+ *
+ * 2. PERF_RECORD_XXX processing triggers access to the auxtrace_queues.
+ * Each record is handled by s390_cpumsf_process_event(). The time stamp of
+ * the perf record is compared with the time stamp located on the auxtrace_heap
+ * top element. If that time stamp is lower than the time stamp from the
+ * record sample, the auxtrace queues will be processed. As auxtrace queues
+ * control many auxtrace_buffers and each buffer can be quite large, the
+ * auxtrace buffer might be processed only partially. In this case the
+ * position in the auxtrace_buffer of that queue is remembered and the time
+ * stamp of the last processed entry of the auxtrace_buffer replaces the
+ * current auxtrace_heap top.
+ *
+ * 3. Auxtrace_queues might run of out data and are feeded by the
+ * PERF_RECORD_AUXTRACE handling, see s390_cpumsf_process_auxtrace_event().
+ *
+ * Event Generation
+ * Each sampling-data entry in the auxilary trace data generates a perf sample.
+ * This sample is filled
+ * with data from the auxtrace such as PID/TID, instruction address, CPU state,
+ * etc. This sample is processed with perf_session__deliver_synth_event() to
+ * be included into the GUI.
+ *
+ * 4. PERF_RECORD_FINISHED_ROUND event is used to process all the remaining
+ * auxiliary traces entries until the time stamp of this record is reached
+ * auxtrace_heap top. This is triggered by ordered_event->deliver().
+ *
+ *
+ * Perf event processing.
+ * Event processing of PERF_RECORD_XXX entries relies on time stamp entries.
+ * This is the function call sequence:
+ *
+ * __cmd_report()
+ * |
+ * perf_session__process_events()
+ * |
+ * __perf_session__process_events()
+ * |
+ * perf_session__process_event()
+ * | This functions splits the PERF_RECORD_XXX records.
+ * | - Those generated by perf record command (type number equal or higher
+ * | than PERF_RECORD_USER_TYPE_START) are handled by
+ * | perf_session__process_user_event(see below)
+ * | - Those generated by the kernel are handled by
+ * | perf_evlist__parse_sample_timestamp()
+ * |
+ * perf_evlist__parse_sample_timestamp()
+ * | Extract time stamp from sample data.
+ * |
+ * perf_session__queue_event()
+ * | If timestamp is positive the sample is entered into an ordered_event
+ * | list, sort order is the timestamp. The event processing is deferred until
+ * | later (see perf_session__process_user_event()).
+ * | Other timestamps (0 or -1) are handled immediately by
+ * | perf_session__deliver_event(). These are events generated at start up
+ * | of command perf record. They create PERF_RECORD_COMM and PERF_RECORD_MMAP*
+ * | records. They are needed to create a list of running processes and its
+ * | memory mappings and layout. They are needed at the beginning to enable
+ * | command perf report to create process trees and memory mappings.
+ * |
+ * perf_session__deliver_event()
+ * | Delivers a PERF_RECORD_XXX entry for handling.
+ * |
+ * auxtrace__process_event()
+ * | The timestamp of the PERF_RECORD_XXX entry is taken to correlate with
+ * | time stamps from the auxiliary trace buffers. This enables
+ * | synchronization between auxiliary trace data and the events on the
+ * | perf.data file.
+ * |
+ * machine__deliver_event()
+ * | Handles the PERF_RECORD_XXX event. This depends on the record type.
+ * It might update the process tree, update a process memory map or enter
+ * a sample with IP and call back chain data into GUI data pool.
+ *
+ *
+ * Deferred processing determined by perf_session__process_user_event() is
+ * finally processed when a PERF_RECORD_FINISHED_ROUND is encountered. These
+ * are generated during command perf record.
+ * The timestamp of PERF_RECORD_FINISHED_ROUND event is taken to process all
+ * PERF_RECORD_XXX entries stored in the ordered_event list. This list was
+ * built up while reading the perf.data file.
+ * Each event is now processed by calling perf_session__deliver_event().
+ * This enables time synchronization between the data in the perf.data file and
+ * the data in the auxiliary trace buffers.
*/
#include <endian.h>
@@ -37,6 +169,14 @@ struct s390_cpumsf {
u32 auxtrace_type;
u32 pmu_type;
u16 machine_type;
+ bool data_queued;
+};
+
+struct s390_cpumsf_queue {
+ struct s390_cpumsf *sf;
+ unsigned int queue_nr;
+ struct auxtrace_buffer *buffer;
+ int cpu;
};
/* Display s390 CPU measurement facility basic-sampling data entry */
@@ -181,8 +321,8 @@ static void s390_cpumsf_dump(struct s390_cpumsf *sf,
const char *color = PERF_COLOR_BLUE;
struct hws_basic_entry *basic;
struct hws_diag_entry *diag;
- size_t pos = 0;
unsigned short bsdes, dsdes;
+ size_t pos = 0;
color_fprintf(stdout, color,
". ... s390 AUX data: size %zu bytes\n",
@@ -243,15 +383,414 @@ static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf,
s390_cpumsf_dump(sf, buf, len);
}
+#define S390_LPP_PID_MASK 0xffffffff
+
+static bool s390_cpumsf_make_event(size_t pos,
+ struct hws_basic_entry *basic,
+ struct s390_cpumsf_queue *sfq)
+{
+ struct perf_sample sample = {
+ .ip = basic->ia,
+ .pid = basic->hpp & S390_LPP_PID_MASK,
+ .tid = basic->hpp & S390_LPP_PID_MASK,
+ .cpumode = PERF_RECORD_MISC_CPUMODE_UNKNOWN,
+ .cpu = sfq->cpu,
+ .period = 1
+ };
+ union perf_event event;
+
+ memset(&event, 0, sizeof(event));
+ if (basic->CL == 1) /* Native LPAR mode */
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
+ : PERF_RECORD_MISC_KERNEL;
+ else if (basic->CL == 2) /* Guest kernel/user space */
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
+ : PERF_RECORD_MISC_GUEST_KERNEL;
+ else if (basic->gpp || basic->prim_asn != 0xffff)
+ /* Use heuristics on old hardware */
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER
+ : PERF_RECORD_MISC_GUEST_KERNEL;
+ else
+ sample.cpumode = basic->P ? PERF_RECORD_MISC_USER
+ : PERF_RECORD_MISC_KERNEL;
+
+ event.sample.header.type = PERF_RECORD_SAMPLE;
+ event.sample.header.misc = sample.cpumode;
+ event.sample.header.size = sizeof(struct perf_event_header);
+
+ pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n",
+ __func__, pos, sample.ip, basic->P, basic->CL, sample.pid,
+ sample.tid, sample.cpumode, sample.cpu);
+ if (perf_session__deliver_synth_event(sfq->sf->session, &event,
+ &sample)) {
+ pr_err("s390 Auxiliary Trace: failed to deliver event\n");
+ return false;
+ }
+ return true;
+}
+
+static unsigned long long get_trailer_time(const unsigned char *buf)
+{
+ struct hws_trailer_entry *te;
+ unsigned long long aux_time;
+
+ te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ
+ - sizeof(*te));
+
+ if (!te->clock_base) /* TOD_CLOCK_BASE value missing */
+ return 0;
+
+ /* Correct calculation to convert time stamp in trailer entry to
+ * nano seconds (taken from arch/s390 function tod_to_ns()).
+ * TOD_CLOCK_BASE is stored in trailer entry member progusage2.
+ */
+ aux_time = trailer_timestamp(te) - te->progusage2;
+ aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9);
+ return aux_time;
+}
+
+/* Process the data samples of a single queue. The first parameter is a
+ * pointer to the queue, the second parameter is the time stamp. This
+ * is the time stamp:
+ * - of the event that triggered this processing.
+ * - or the time stamp when the last proccesing of this queue stopped.
+ * In this case it stopped at a 4KB page boundary and record the
+ * position on where to continue processing on the next invocation
+ * (see buffer->use_data and buffer->use_size).
+ *
+ * When this function returns the second parameter is updated to
+ * reflect the time stamp of the last processed auxiliary data entry
+ * (taken from the trailer entry of that page). The caller uses this
+ * returned time stamp to record the last processed entry in this
+ * queue.
+ *
+ * The function returns:
+ * 0: Processing successful. The second parameter returns the
+ * time stamp from the trailer entry until which position
+ * processing took place. Subsequent calls resume from this
+ * position.
+ * <0: An error occurred during processing. The second parameter
+ * returns the maximum time stamp.
+ * >0: Done on this queue. The second parameter returns the
+ * maximum time stamp.
+ */
+static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts)
+{
+ struct s390_cpumsf *sf = sfq->sf;
+ unsigned char *buf = sfq->buffer->use_data;
+ size_t len = sfq->buffer->use_size;
+ struct hws_basic_entry *basic;
+ unsigned short bsdes, dsdes;
+ size_t pos = 0;
+ int err = 1;
+ u64 aux_ts;
+
+ if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes,
+ &dsdes)) {
+ *ts = ~0ULL;
+ return -1;
+ }
+
+ /* Get trailer entry time stamp and check if entries in
+ * this auxiliary page are ready for processing. If the
+ * time stamp of the first entry is too high, whole buffer
+ * can be skipped. In this case return time stamp.
+ */
+ aux_ts = get_trailer_time(buf);
+ if (!aux_ts) {
+ pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n",
+ sfq->buffer->data_offset);
+ aux_ts = ~0ULL;
+ goto out;
+ }
+ if (aux_ts > *ts) {
+ *ts = aux_ts;
+ return 0;
+ }
+
+ while (pos < len) {
+ /* Handle Basic entry */
+ basic = (struct hws_basic_entry *)(buf + pos);
+ if (s390_cpumsf_make_event(pos, basic, sfq))
+ pos += bsdes;
+ else {
+ err = -EBADF;
+ goto out;
+ }
+
+ pos += dsdes; /* Skip diagnositic entry */
+
+ /* Check for trailer entry */
+ if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) {
+ pos = (pos + S390_CPUMSF_PAGESZ)
+ & ~(S390_CPUMSF_PAGESZ - 1);
+ /* Check existence of next page */
+ if (pos >= len)
+ break;
+ aux_ts = get_trailer_time(buf + pos);
+ if (!aux_ts) {
+ aux_ts = ~0ULL;
+ goto out;
+ }
+ if (aux_ts > *ts) {
+ *ts = aux_ts;
+ sfq->buffer->use_data += pos;
+ sfq->buffer->use_size -= pos;
+ return 0;
+ }
+ }
+ }
+out:
+ *ts = aux_ts;
+ sfq->buffer->use_size = 0;
+ sfq->buffer->use_data = NULL;
+ return err; /* Buffer completely scanned or error */
+}
+
+/* Run the s390 auxiliary trace decoder.
+ * Select the queue buffer to operate on, the caller already selected
+ * the proper queue, depending on second parameter 'ts'.
+ * This is the time stamp until which the auxiliary entries should
+ * be processed. This value is updated by called functions and
+ * returned to the caller.
+ *
+ * Resume processing in the current buffer. If there is no buffer
+ * get a new buffer from the queue and setup start position for
+ * processing.
+ * When a buffer is completely processed remove it from the queue
+ * before returning.
+ *
+ * This function returns
+ * 1: When the queue is empty. Second parameter will be set to
+ * maximum time stamp.
+ * 0: Normal processing done.
+ * <0: Error during queue buffer setup. This causes the caller
+ * to stop processing completely.
+ */
+static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq,
+ u64 *ts)
+{
+
+ struct auxtrace_buffer *buffer;
+ struct auxtrace_queue *queue;
+ int err;
+
+ queue = &sfq->sf->queues.queue_array[sfq->queue_nr];
+
+ /* Get buffer and last position in buffer to resume
+ * decoding the auxiliary entries. One buffer might be large
+ * and decoding might stop in between. This depends on the time
+ * stamp of the trailer entry in each page of the auxiliary
+ * data and the time stamp of the event triggering the decoding.
+ */
+ if (sfq->buffer == NULL) {
+ sfq->buffer = buffer = auxtrace_buffer__next(queue,
+ sfq->buffer);
+ if (!buffer) {
+ *ts = ~0ULL;
+ return 1; /* Processing done on this queue */
+ }
+ /* Start with a new buffer on this queue */
+ if (buffer->data) {
+ buffer->use_size = buffer->size;
+ buffer->use_data = buffer->data;
+ }
+ } else
+ buffer = sfq->buffer;
+
+ if (!buffer->data) {
+ int fd = perf_data__fd(sfq->sf->session->data);
+
+ buffer->data = auxtrace_buffer__get_data(buffer, fd);
+ if (!buffer->data)
+ return -ENOMEM;
+ buffer->use_size = buffer->size;
+ buffer->use_data = buffer->data;
+ }
+ pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n",
+ __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset,
+ buffer->size, buffer->use_size);
+ err = s390_cpumsf_samples(sfq, ts);
+
+ /* If non-zero, there is either an error (err < 0) or the buffer is
+ * completely done (err > 0). The error is unrecoverable, usually
+ * some descriptors could not be read successfully, so continue with
+ * the next buffer.
+ * In both cases the parameter 'ts' has been updated.
+ */
+ if (err) {
+ sfq->buffer = NULL;
+ list_del(&buffer->list);
+ auxtrace_buffer__free(buffer);
+ if (err > 0) /* Buffer done, no error */
+ err = 0;
+ }
+ return err;
+}
+
+static struct s390_cpumsf_queue *
+s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr)
+{
+ struct s390_cpumsf_queue *sfq;
+
+ sfq = zalloc(sizeof(struct s390_cpumsf_queue));
+ if (sfq == NULL)
+ return NULL;
+
+ sfq->sf = sf;
+ sfq->queue_nr = queue_nr;
+ sfq->cpu = -1;
+ return sfq;
+}
+
+static int s390_cpumsf_setup_queue(struct s390_cpumsf *sf,
+ struct auxtrace_queue *queue,
+ unsigned int queue_nr, u64 ts)
+{
+ struct s390_cpumsf_queue *sfq = queue->priv;
+
+ if (list_empty(&queue->head))
+ return 0;
+
+ if (sfq == NULL) {
+ sfq = s390_cpumsf_alloc_queue(sf, queue_nr);
+ if (!sfq)
+ return -ENOMEM;
+ queue->priv = sfq;
+
+ if (queue->cpu != -1)
+ sfq->cpu = queue->cpu;
+ }
+ return auxtrace_heap__add(&sf->heap, queue_nr, ts);
+}
+
+static int s390_cpumsf_setup_queues(struct s390_cpumsf *sf, u64 ts)
+{
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < sf->queues.nr_queues; i++) {
+ ret = s390_cpumsf_setup_queue(sf, &sf->queues.queue_array[i],
+ i, ts);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static int s390_cpumsf_update_queues(struct s390_cpumsf *sf, u64 ts)
+{
+ if (!sf->queues.new_data)
+ return 0;
+
+ sf->queues.new_data = false;
+ return s390_cpumsf_setup_queues(sf, ts);
+}
+
+static int s390_cpumsf_process_queues(struct s390_cpumsf *sf, u64 timestamp)
+{
+ unsigned int queue_nr;
+ u64 ts;
+ int ret;
+
+ while (1) {
+ struct auxtrace_queue *queue;
+ struct s390_cpumsf_queue *sfq;
+
+ if (!sf->heap.heap_cnt)
+ return 0;
+
+ if (sf->heap.heap_array[0].ordinal >= timestamp)
+ return 0;
+
+ queue_nr = sf->heap.heap_array[0].queue_nr;
+ queue = &sf->queues.queue_array[queue_nr];
+ sfq = queue->priv;
+
+ auxtrace_heap__pop(&sf->heap);
+ if (sf->heap.heap_cnt) {
+ ts = sf->heap.heap_array[0].ordinal + 1;
+ if (ts > timestamp)
+ ts = timestamp;
+ } else {
+ ts = timestamp;
+ }
+
+ ret = s390_cpumsf_run_decoder(sfq, &ts);
+ if (ret < 0) {
+ auxtrace_heap__add(&sf->heap, queue_nr, ts);
+ return ret;
+ }
+ if (!ret) {
+ ret = auxtrace_heap__add(&sf->heap, queue_nr, ts);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int s390_cpumsf_synth_error(struct s390_cpumsf *sf, int code, int cpu,
+ pid_t pid, pid_t tid, u64 ip)
+{
+ char msg[MAX_AUXTRACE_ERROR_MSG];
+ union perf_event event;
+ int err;
+
+ strncpy(msg, "Lost Auxiliary Trace Buffer", sizeof(msg) - 1);
+ auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE,
+ code, cpu, pid, tid, ip, msg);
+
+ err = perf_session__deliver_synth_event(sf->session, &event, NULL);
+ if (err)
+ pr_err("s390 Auxiliary Trace: failed to deliver error event,"
+ "error %d\n", err);
+ return err;
+}
+
+static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample)
+{
+ return s390_cpumsf_synth_error(sf, 1, sample->cpu,
+ sample->pid, sample->tid, 0);
+}
+
static int
s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
- union perf_event *event __maybe_unused,
- struct perf_sample *sample __maybe_unused,
- struct perf_tool *tool __maybe_unused)
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_tool *tool)
{
- return 0;
+ struct s390_cpumsf *sf = container_of(session->auxtrace,
+ struct s390_cpumsf,
+ auxtrace);
+ u64 timestamp = sample->time;
+ int err = 0;
+
+ if (dump_trace)
+ return 0;
+
+ if (!tool->ordered_events) {
+ pr_err("s390 Auxiliary Trace requires ordered events\n");
+ return -EINVAL;
+ }
+
+ if (event->header.type == PERF_RECORD_AUX &&
+ event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
+ return s390_cpumsf_lost(sf, sample);
+
+ if (timestamp) {
+ err = s390_cpumsf_update_queues(sf, timestamp);
+ if (!err)
+ err = s390_cpumsf_process_queues(sf, timestamp);
+ }
+ return err;
}
+struct s390_cpumsf_synth {
+ struct perf_tool cpumsf_tool;
+ struct perf_session *session;
+};
+
static int
s390_cpumsf_process_auxtrace_event(struct perf_session *session,
union perf_event *event __maybe_unused,
@@ -266,6 +805,9 @@ s390_cpumsf_process_auxtrace_event(struct perf_session *session,
off_t data_offset;
int err;
+ if (sf->data_queued)
+ return 0;
+
if (perf_data__is_pipe(session->data)) {
data_offset = 0;
} else {
@@ -290,17 +832,21 @@ s390_cpumsf_process_auxtrace_event(struct perf_session *session,
return 0;
}
+static void s390_cpumsf_free_events(struct perf_session *session __maybe_unused)
+{
+}
+
static int s390_cpumsf_flush(struct perf_session *session __maybe_unused,
struct perf_tool *tool __maybe_unused)
{
return 0;
}
-static void s390_cpumsf_free_events(struct perf_session *session)
+static void s390_cpumsf_free_queues(struct perf_session *session)
{
struct s390_cpumsf *sf = container_of(session->auxtrace,
struct s390_cpumsf,
- auxtrace);
+ auxtrace);
struct auxtrace_queues *queues = &sf->queues;
unsigned int i;
@@ -316,7 +862,7 @@ static void s390_cpumsf_free(struct perf_session *session)
auxtrace);
auxtrace_heap__free(&sf->heap);
- s390_cpumsf_free_events(session);
+ s390_cpumsf_free_queues(session);
session->auxtrace = NULL;
free(sf);
}
@@ -329,6 +875,19 @@ static int s390_cpumsf_get_type(const char *cpuid)
return (ret == 1) ? family : 0;
}
+/* Check itrace options set on perf report command.
+ * Return true, if none are set or all options specified can be
+ * handled on s390.
+ * Return false otherwise.
+ */
+static bool check_auxtrace_itrace(struct itrace_synth_opts *itops)
+{
+ if (!itops || !itops->set)
+ return true;
+ pr_err("No --itrace options supported\n");
+ return false;
+}
+
int s390_cpumsf_process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
@@ -343,6 +902,11 @@ int s390_cpumsf_process_auxtrace_info(union perf_event *event,
if (sf == NULL)
return -ENOMEM;
+ if (!check_auxtrace_itrace(session->itrace_synth_opts)) {
+ err = -EINVAL;
+ goto err_free;
+ }
+
err = auxtrace_queues__init(&sf->queues);
if (err)
goto err_free;
@@ -360,8 +924,21 @@ int s390_cpumsf_process_auxtrace_info(union perf_event *event,
sf->auxtrace.free = s390_cpumsf_free;
session->auxtrace = &sf->auxtrace;
+ if (dump_trace)
+ return 0;
+
+ err = auxtrace_queues__process_index(&sf->queues, session);
+ if (err)
+ goto err_free_queues;
+
+ if (sf->queues.populated)
+ sf->data_queued = true;
+
return 0;
+err_free_queues:
+ auxtrace_queues__free(&sf->queues);
+ session->auxtrace = NULL;
err_free:
free(sf);
return err;