2019-01-17 09:50:01

by Thomas Richter

[permalink] [raw]
Subject: [Patchv2 0/3] perf report: Display CPU Measurement facility counter sets

The CPU Measurement facility for counters supports the extraction
of complete counter sets via hardware instruction STCCTM (if
available).

This patch set displays the counter sets in the perf report tool.

V1 --> V2
1. Repackage event decoding and create an s390 specific file
util/s390-sample-raw.c. It decodes the counter sets and is located
in the common tree to enable decoding on other platforms (x86) as
well.
2. Patch 3 unchanged

Thomas Richter (3):
perf report: Display s390 diagnostic counter sets
perf report: Display names in s390 diagnostic counter sets
perf/report: s390 dump counter set data to file.

--
2.14.3



2019-01-17 09:49:27

by Thomas Richter

[permalink] [raw]
Subject: [PATCHv2 3/3] perf report: s390 dump counter set data to file.

Add support for the new s390 PMU device cpum_cf_diag to extract
the counter set diagnostic data. This data is available as event
raw data and can be created with this command:

[root@s35lp76 perf]# ./perf record -R -e '{rbd000,rbc000}' --
~/mytests/facultaet 2500
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.009 MB perf.data ]
[root@s35lp76 perf]#

The new event 0xbc000 generated this counter set diagnostic
trace data. The data can be extracted using command:

[root@s35lp76 perf]# ./perf report --stdio --itrace=d
#
# Total Lost Samples: 0
#
# Samples: 21 of events 'anon group { rbd000, rbc000 }'
# Event count (approx.): 21
#
# Overhead Command Shared Object Symbol
# ................ ......... ................. ........................
#
80.95% 0.00% facultaet facultaet [.] facultaet
4.76% 0.00% facultaet [kernel.kallsyms] [k] check_chain_key
4.76% 0.00% facultaet [kernel.kallsyms] [k] ftrace_likely_update
4.76% 0.00% facultaet [kernel.kallsyms] [k] lock_release
4.76% 0.00% facultaet libc-2.26.so [.] _dl_addr
[root@s35lp76 perf]# ll aux*
-rw-r--r-- 1 root root 3408 Oct 16 12:40 aux.ctr.02
-rw-r--r-- 1 root root 4096 Oct 16 12:40 aux.smp.02
[root@s35lp76 perf]#

The files named aux.ctr.## contain the counter set diagnstic
data and the files named aux.smp.## contain the sampling
diagnostic data. ## stand for the CPU number the data was
taken from.

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/util/s390-cpumsf.c | 77 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 73 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index 68b2570304ec..835249c77f56 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -162,6 +162,7 @@
#include "auxtrace.h"
#include "s390-cpumsf.h"
#include "s390-cpumsf-kernel.h"
+#include "s390-cpumcf-kernel.h"
#include "config.h"

struct s390_cpumsf {
@@ -184,8 +185,58 @@ struct s390_cpumsf_queue {
struct auxtrace_buffer *buffer;
int cpu;
FILE *logfile;
+ FILE *logfile_ctr;
};

+/* Check if the raw data should be dumped to file. If this is the case and
+ * the file to dump to has not been opened for writing, do so.
+ *
+ * Return 0 on success and greater zero on error so processing continues.
+ */
+static int s390_cpumcf_dumpctr(struct s390_cpumsf *sf,
+ struct perf_sample *sample)
+{
+ struct s390_cpumsf_queue *sfq;
+ struct auxtrace_queue *q;
+ int rc = 0;
+
+ if (!sf->use_logfile || sf->queues.nr_queues <= sample->cpu)
+ return rc;
+
+ q = &sf->queues.queue_array[sample->cpu];
+ sfq = q->priv;
+ if (!sfq) /* Queue not yet allocated */
+ return rc;
+
+ if (!sfq->logfile_ctr) {
+ char *name;
+
+ rc = (sf->logdir)
+ ? asprintf(&name, "%s/aux.ctr.%02x",
+ sf->logdir, sample->cpu)
+ : asprintf(&name, "aux.ctr.%02x", sample->cpu);
+ if (rc > 0)
+ sfq->logfile_ctr = fopen(name, "w");
+ if (sfq->logfile_ctr == NULL) {
+ pr_err("Failed to open counter set log file %s, "
+ "continue...\n", name);
+ rc = 1;
+ }
+ free(name);
+ }
+
+ if (sfq->logfile_ctr) {
+ /* See comment above for -4 */
+ size_t n = fwrite(sample->raw_data, sample->raw_size - 4, 1,
+ sfq->logfile_ctr);
+ if (n != 1) {
+ pr_err("Failed to write counter set data\n");
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
/* 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)
@@ -792,7 +843,7 @@ static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample)
}

static int
-s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
+s390_cpumsf_process_event(struct perf_session *session,
union perf_event *event,
struct perf_sample *sample,
struct perf_tool *tool)
@@ -801,6 +852,8 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
struct s390_cpumsf,
auxtrace);
u64 timestamp = sample->time;
+ struct perf_evsel *ev_bc000;
+
int err = 0;

if (dump_trace)
@@ -811,6 +864,16 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
return -EINVAL;
}

+ if (event->header.type == PERF_RECORD_SAMPLE &&
+ sample->raw_size) {
+ /* Handle event with raw data */
+ ev_bc000 = perf_evlist__event2evsel(session->evlist, event);
+ if (ev_bc000 &&
+ ev_bc000->attr.config == PERF_EVENT_CPUM_CF_DIAG)
+ err = s390_cpumcf_dumpctr(sf, sample);
+ return err;
+ }
+
if (event->header.type == PERF_RECORD_AUX &&
event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
return s390_cpumsf_lost(sf, sample);
@@ -891,9 +954,15 @@ static void s390_cpumsf_free_queues(struct perf_session *session)
struct s390_cpumsf_queue *sfq = (struct s390_cpumsf_queue *)
queues->queue_array[i].priv;

- if (sfq != NULL && sfq->logfile) {
- fclose(sfq->logfile);
- sfq->logfile = NULL;
+ if (sfq != NULL) {
+ if (sfq->logfile) {
+ fclose(sfq->logfile);
+ sfq->logfile = NULL;
+ }
+ if (sfq->logfile_ctr) {
+ fclose(sfq->logfile_ctr);
+ sfq->logfile_ctr = NULL;
+ }
}
zfree(&queues->queue_array[i].priv);
}
--
2.14.3


2019-01-17 09:49:32

by Thomas Richter

[permalink] [raw]
Subject: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

On s390 the event bc000 (also named CF_DIAG)
extracts the CPU Measurement Facility diagnostic counter sets
and displays them as counter number and counter value
pairs sorted by counter set number.

Output:
[root@s35lp76 perf]# ./perf report -D --stdio

[00000000] Counterset:0 Counters:6
Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000
Counter:002 Value:000000000000000000 Counter:003 Value:000000000000000000
Counter:004 Value:000000000000000000 Counter:005 Value:000000000000000000
Counter:006 Value:000000000000000000 Counter:007 Value:000000000000000000
Counter:008 Value:000000000000000000 Counter:009 Value:000000000000000000
Counter:010 Value:000000000000000000 Counter:011 Value:000000000000000000
Counter:012 Value:000000000000000000 Counter:013 Value:000000000000000000
Counter:014 Value:000000000000000000 Counter:015 Value:000000000000000000
[0x0000d8] Counterset:3 Counters:128
Counter:000 Value:0x000000000000020f Counter:001 Value:0x00000000000001d8
Counter:002 Value:0x000000000000d7fa Counter:003 Value:0x000000000000008b
...

The number in brackets is the offset into the raw data field
of the sample.

New functions trace_event_sample_raw() and s390_sample_raw() are
introduced in the code path to enable interpretation on non s390
platforms. This event bc000 attached raw data is generated only
on s390 platform. Correct display on other platforms requires
correct endianness handling.

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/util/Build | 2 +
tools/perf/util/s390-cpumcf-kernel.h | 62 +++++++++++
tools/perf/util/s390-sample-raw.c | 172 +++++++++++++++++++++++++++++++
tools/perf/util/session.c | 2 +
tools/perf/util/session.h | 5 +
tools/perf/util/trace-event-sample-raw.c | 30 ++++++
6 files changed, 273 insertions(+)
create mode 100644 tools/perf/util/s390-cpumcf-kernel.h
create mode 100644 tools/perf/util/s390-sample-raw.c
create mode 100644 tools/perf/util/trace-event-sample-raw.c

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index af72be7f5b3b..d6a11099919c 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -44,6 +44,8 @@ libperf-y += machine.o
libperf-y += map.o
libperf-y += pstack.o
libperf-y += session.o
+libperf-y += trace-event-sample-raw.o
+libperf-y += s390-sample-raw.o
libperf-$(CONFIG_TRACE) += syscalltbl.o
libperf-y += ordered-events.o
libperf-y += namespaces.o
diff --git a/tools/perf/util/s390-cpumcf-kernel.h b/tools/perf/util/s390-cpumcf-kernel.h
new file mode 100644
index 000000000000..d4356030b504
--- /dev/null
+++ b/tools/perf/util/s390-cpumcf-kernel.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for s390 CPU measurement counter set diagnostic facility
+ *
+ * Copyright IBM Corp. 2019
+ Author(s): Hendrik Brueckner <[email protected]>
+ * Thomas Richter <[email protected]>
+ */
+#ifndef S390_CPUMCF_KERNEL_H
+#define S390_CPUMCF_KERNEL_H
+
+#define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */
+#define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */
+
+struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int set:16; /* 16-23 Counter set identifier */
+ unsigned int ctr:16; /* 24-39 Number of stored counters */
+ unsigned int res1:16; /* 40-63 Reserved */
+};
+
+struct cf_trailer_entry { /* CPU-M CF trailer for raw traces (64 byte) */
+ /* 0 - 7 */
+ union {
+ struct {
+ unsigned int clock_base:1; /* TOD clock base */
+ unsigned int speed:1; /* CPU speed */
+ /* Measurement alerts */
+ unsigned int mtda:1; /* Loss of MT ctr. data alert */
+ unsigned int caca:1; /* Counter auth. change alert */
+ unsigned int lcda:1; /* Loss of counter data alert */
+ };
+ unsigned long flags; /* 0-63 All indicators */
+ };
+ /* 8 - 15 */
+ unsigned int cfvn:16; /* 64-79 Ctr First Version */
+ unsigned int csvn:16; /* 80-95 Ctr Second Version */
+ unsigned int cpu_speed:32; /* 96-127 CPU speed */
+ /* 16 - 23 */
+ unsigned long timestamp; /* 128-191 Timestamp (TOD) */
+ /* 24 - 55 */
+ union {
+ struct {
+ unsigned long progusage1;
+ unsigned long progusage2;
+ unsigned long progusage3;
+ unsigned long tod_base;
+ };
+ unsigned long progusage[4];
+ };
+ /* 56 - 63 */
+ unsigned int mach_type:16; /* Machine type */
+ unsigned int res1:16; /* Reserved */
+ unsigned int res2:32; /* Reserved */
+};
+
+#define CPUMF_CTR_SET_BASIC 0 /* Basic Counter Set */
+#define CPUMF_CTR_SET_USER 1 /* Problem-State Counter Set */
+#define CPUMF_CTR_SET_CRYPTO 2 /* Crypto-Activity Counter Set */
+#define CPUMF_CTR_SET_EXT 3 /* Extended Counter Set */
+#define CPUMF_CTR_SET_MT_DIAG 4 /* MT-diagnostic Counter Set */
+#endif
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
new file mode 100644
index 000000000000..ae16c38ce296
--- /dev/null
+++ b/tools/perf/util/s390-sample-raw.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2019
+ * Author(s): Thomas Richter <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Architecture specific trace_event function. Save event's bc000 raw data
+ * to file. File name is aux.ctr.## where ## stands for the CPU number the
+ * sample was taken from.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <sys/stat.h>
+#include <asm/byteorder.h>
+
+#include "debug.h"
+#include "util.h"
+#include "auxtrace.h"
+#include "session.h"
+#include "evlist.h"
+#include "config.h"
+#include "color.h"
+#include "s390-cpumcf-kernel.h"
+
+static size_t ctrset_size(struct cf_ctrset_entry *set)
+{
+ return sizeof(*set) + set->ctr * sizeof(u64);
+}
+
+static bool ctrset_valid(struct cf_ctrset_entry *set)
+{
+ return set->def == S390_CPUMCF_DIAG_DEF;
+}
+
+/* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte
+ * aligned and might have trailing padding bytes.
+ * Display the raw data on screen.
+ */
+static bool s390_cpumcfdg_testctr(struct perf_sample *sample)
+{
+ size_t len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ struct cf_trailer_entry *te;
+ struct cf_ctrset_entry *cep, ce;
+
+ if (!len)
+ return false;
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) {
+ /* Raw data for counter sets are always multiple of 8
+ * bytes. Prepending a 4 bytes size field to the
+ * raw data block in the sample causes the perf tool
+ * to append 4 padding bytes to make the raw data part
+ * of the sample a multiple of eight bytes again.
+ *
+ * If the last entry (trailer) is 4 bytes off the raw
+ * area data end, all is good.
+ */
+ if (len - offset - sizeof(*te) == 4)
+ break;
+ pr_err("Invalid counter set entry at %#" PRIx64 "\n",
+ offset);
+ return false;
+ }
+ offset += ctrset_size(&ce);
+ }
+ return true;
+}
+
+/* Dump event bc000 on screen, already tested on correctness. */
+static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,
+ struct cf_trailer_entry *tep)
+{
+ struct cf_trailer_entry te;
+
+ te.flags = be64_to_cpu(tep->flags);
+ te.cfvn = be16_to_cpu(tep->cfvn);
+ te.csvn = be16_to_cpu(tep->csvn);
+ te.cpu_speed = be32_to_cpu(tep->cpu_speed);
+ te.timestamp = be64_to_cpu(tep->timestamp);
+ te.progusage1 = be64_to_cpu(tep->progusage1);
+ te.progusage2 = be64_to_cpu(tep->progusage2);
+ te.progusage3 = be64_to_cpu(tep->progusage3);
+ te.tod_base = be64_to_cpu(tep->tod_base);
+ te.mach_type = be16_to_cpu(tep->mach_type);
+ te.res1 = be16_to_cpu(tep->res1);
+ te.res2 = be32_to_cpu(tep->res2);
+
+ color_fprintf(stdout, color, " [%#08zx] Trailer:%c%c%c%c%c"
+ " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n",
+ offset, te.clock_base ? 'T' : ' ',
+ te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ',
+ te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ',
+ te.cfvn, te.csvn, te.cpu_speed, te.timestamp);
+ color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx"
+ " Type:%x\n\n",
+ te.progusage1, te.progusage2, te.progusage3,
+ te.tod_base, te.mach_type);
+}
+
+static void s390_cpumcfdg_dump(struct perf_sample *sample)
+{
+ size_t i, len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ const char *color = PERF_COLOR_BLUE;
+ struct cf_ctrset_entry *cep, ce;
+ u64 *p;
+
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce)) { /* Print trailer */
+ s390_cpumcfdg_dumptrail(color, offset,
+ (struct cf_trailer_entry *)cep);
+ return;
+ }
+
+ color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
+ " Counters:%d\n", offset, ce.set, ce.ctr);
+ for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; i += 2, p += 2)
+ color_fprintf(stdout, color,
+ "\tCounter:%03d Value:%#018lx"
+ " Counter:%03d Value:%#018lx\n",
+ i, be64_to_cpu(*p),
+ i + 1, be64_to_cpu(*(p + 1)));
+ offset += ctrset_size(&ce);
+ }
+}
+
+/* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events
+ * and if the event was triggered by a counter set diagnostic event display
+ * its raw data.
+ * The function is only invoked when the dump flag -D is set.
+ */
+void s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample)
+{
+ struct perf_evsel *ev_bc000;
+
+ if (event->header.type != PERF_RECORD_SAMPLE)
+ return;
+
+ ev_bc000 = perf_evlist__event2evsel(evlist, event);
+ if (ev_bc000 == NULL ||
+ ev_bc000->attr.config != PERF_EVENT_CPUM_CF_DIAG)
+ return;
+
+ /* Display raw data on screen */
+ if (!s390_cpumcfdg_testctr(sample)) {
+ pr_err("Invalid counter set data encountered\n");
+ return;
+ }
+ s390_cpumcfdg_dump(sample);
+}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5456c84c7dd1..f0c71c6f670a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1065,6 +1065,8 @@ static void dump_event(struct perf_evlist *evlist, union perf_event *event,
file_offset, event->header.size, event->header.type);

trace_event(event);
+ if (event->header.type == PERF_RECORD_SAMPLE)
+ trace_event_sample_raw(evlist, event, sample);

if (sample)
perf_evlist__print_tstamp(evlist, event, sample);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index d96eccd7d27f..dbd7256c82f6 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -128,4 +128,9 @@ int perf_event__synthesize_id_index(struct perf_tool *tool,
struct perf_evlist *evlist,
struct machine *machine);

+void trace_event_sample_raw(struct perf_evlist *evlist __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_sample *sample __maybe_unused);
+void s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample);
#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/trace-event-sample-raw.c b/tools/perf/util/trace-event-sample-raw.c
new file mode 100644
index 000000000000..622471a02267
--- /dev/null
+++ b/tools/perf/util/trace-event-sample-raw.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2019
+ * Author(s): Thomas Richter <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Architecture specific trace_event function. Save event's bc000 raw data
+ * to file. File name is aux.ctr.## where ## stands for the CPU number the
+ * sample was taken from.
+ */
+
+#include <string.h>
+
+#include "session.h"
+#include "evlist.h"
+
+/* Check platform the perf data file was created on and perform platform
+ * specific interpretation.
+ */
+void trace_event_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample)
+{
+ const char *arch_pf = perf_env__arch(evlist->env);
+
+ if (arch_pf && !strcmp("s390", arch_pf))
+ s390_sample_raw(evlist, event, sample);
+}
--
2.14.3


2019-01-17 09:50:10

by Thomas Richter

[permalink] [raw]
Subject: [PATCHv2 2/3] perf report: Display names in s390 diagnostic counter sets

On s390 the CPU Measurement Facility diagnostic counter sets are
displayed by counter number and value. Add the logical counter name
in the output (if it is available). Otherwise "unknown" is shown.

Output before:
[root@s35lp76 perf]# ./perf report -D --stdio
[00000000] Counterset:0 Counters:6
Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000

Output after:
[root@s35lp76 perf]# ./perf report -D --stdio

[00000000] Counterset:0 Counters:6
Counter:000 cpu_cycles Value:0x000000000085ec36
Counter:001 instructions Value:0x0000000000796c94
Counter:002 l1i_dir_writes Value:0x0000000000005ada
Counter:003 l1i_penalty_cycles Value:0x0000000000092460
Counter:004 l1d_dir_writes Value:0x0000000000006073
Counter:005 l1d_penalty_cycles Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 problem_state_cpu_cycles Value:0x000000000007c59f
Counter:001 problem_state_instructions Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 prng_functions Value:000000000000000000

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/util/s390-sample-raw.c | 59 +++++++++++++++++++++++++++++++++++----
1 file changed, 54 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index ae16c38ce296..73797bda919d 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -28,6 +28,7 @@
#include "config.h"
#include "color.h"
#include "s390-cpumcf-kernel.h"
+#include "pmu-events/pmu-events.h"

static size_t ctrset_size(struct cf_ctrset_entry *set)
{
@@ -111,14 +112,61 @@ static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,
te.tod_base, te.mach_type);
}

+/* Return starting number of a counter set */
+static int get_counterset_start(int setnr)
+{
+ switch (setnr) {
+ case CPUMF_CTR_SET_BASIC: /* Basic counter set */
+ return 0;
+ case CPUMF_CTR_SET_USER: /* Problem state counter set */
+ return 32;
+ case CPUMF_CTR_SET_CRYPTO: /* Crypto counter set */
+ return 64;
+ case CPUMF_CTR_SET_EXT: /* Extended counter set */
+ return 128;
+ case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */
+ return 448;
+ default:
+ return -1;
+ }
+}
+
+/* Scan the PMU table and extract the logical name of a counter from the
+ * PMU events table. Input is the counter set and counter number with in the
+ * set. Construct the event number and use this as key. If they match return
+ * the name of this counter.
+ * If no match is found a NULL pointer is returned.
+ */
+static const char *get_counter_name(int set, int nr, struct pmu_events_map *map)
+{
+ int rc, event_nr, wanted = get_counterset_start(set) + nr;
+
+ if (map) {
+ struct pmu_event *evp = map->table;
+
+ for (; evp->name || evp->event || evp->desc; ++evp) {
+ if (evp->name == NULL || evp->event == NULL)
+ continue;
+ rc = sscanf(evp->event, "event=%x", &event_nr);
+ if (rc == 1 && event_nr == wanted)
+ return evp->name;
+ }
+ }
+ return NULL;
+}
+
static void s390_cpumcfdg_dump(struct perf_sample *sample)
{
size_t i, len = sample->raw_size, offset = 0;
unsigned char *buf = sample->raw_data;
const char *color = PERF_COLOR_BLUE;
struct cf_ctrset_entry *cep, ce;
+ struct pmu_events_map *map;
+ struct perf_pmu pmu;
u64 *p;

+ memset(&pmu, 0, sizeof(pmu));
+ map = perf_pmu__find_map(&pmu);
while (offset < len) {
cep = (struct cf_ctrset_entry *)(buf + offset);

@@ -135,12 +183,13 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)

color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
" Counters:%d\n", offset, ce.set, ce.ctr);
- for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; i += 2, p += 2)
+ for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
+ const char *ev_name = get_counter_name(ce.set, i, map);
+
color_fprintf(stdout, color,
- "\tCounter:%03d Value:%#018lx"
- " Counter:%03d Value:%#018lx\n",
- i, be64_to_cpu(*p),
- i + 1, be64_to_cpu(*(p + 1)));
+ "\tCounter:%03d %s Value:%#018lx\n", i,
+ ev_name ?: "<unknown>", be64_to_cpu(*p));
+ }
offset += ctrset_size(&ce);
}
}
--
2.14.3


2019-01-17 14:09:49

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCHv2 2/3] perf report: Display names in s390 diagnostic counter sets

Em Thu, Jan 17, 2019 at 10:30:02AM +0100, Thomas Richter escreveu:
> On s390 the CPU Measurement Facility diagnostic counter sets are
> displayed by counter number and value. Add the logical counter name
> in the output (if it is available). Otherwise "unknown" is shown.

Thanks, applied.

> Output before:
> [root@s35lp76 perf]# ./perf report -D --stdio
> [00000000] Counterset:0 Counters:6
> Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
> Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
> Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
> [0x000038] Counterset:1 Counters:2
> Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
> [0x000050] Counterset:2 Counters:16
> Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000
>
> Output after:
> [root@s35lp76 perf]# ./perf report -D --stdio
>
> [00000000] Counterset:0 Counters:6
> Counter:000 cpu_cycles Value:0x000000000085ec36
> Counter:001 instructions Value:0x0000000000796c94
> Counter:002 l1i_dir_writes Value:0x0000000000005ada
> Counter:003 l1i_penalty_cycles Value:0x0000000000092460
> Counter:004 l1d_dir_writes Value:0x0000000000006073
> Counter:005 l1d_penalty_cycles Value:0x00000000001a9a73
> [0x000038] Counterset:1 Counters:2
> Counter:000 problem_state_cpu_cycles Value:0x000000000007c59f
> Counter:001 problem_state_instructions Value:0x000000000002fad6
> [0x000050] Counterset:2 Counters:16
> Counter:000 prng_functions Value:000000000000000000
>
> Signed-off-by: Thomas Richter <[email protected]>
> Reviewed-by: Hendrik Brueckner <[email protected]>
> ---
> tools/perf/util/s390-sample-raw.c | 59 +++++++++++++++++++++++++++++++++++----
> 1 file changed, 54 insertions(+), 5 deletions(-)
>
> diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
> index ae16c38ce296..73797bda919d 100644
> --- a/tools/perf/util/s390-sample-raw.c
> +++ b/tools/perf/util/s390-sample-raw.c
> @@ -28,6 +28,7 @@
> #include "config.h"
> #include "color.h"
> #include "s390-cpumcf-kernel.h"
> +#include "pmu-events/pmu-events.h"
>
> static size_t ctrset_size(struct cf_ctrset_entry *set)
> {
> @@ -111,14 +112,61 @@ static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,
> te.tod_base, te.mach_type);
> }
>
> +/* Return starting number of a counter set */
> +static int get_counterset_start(int setnr)
> +{
> + switch (setnr) {
> + case CPUMF_CTR_SET_BASIC: /* Basic counter set */
> + return 0;
> + case CPUMF_CTR_SET_USER: /* Problem state counter set */
> + return 32;
> + case CPUMF_CTR_SET_CRYPTO: /* Crypto counter set */
> + return 64;
> + case CPUMF_CTR_SET_EXT: /* Extended counter set */
> + return 128;
> + case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */
> + return 448;
> + default:
> + return -1;
> + }
> +}
> +
> +/* Scan the PMU table and extract the logical name of a counter from the
> + * PMU events table. Input is the counter set and counter number with in the
> + * set. Construct the event number and use this as key. If they match return
> + * the name of this counter.
> + * If no match is found a NULL pointer is returned.
> + */
> +static const char *get_counter_name(int set, int nr, struct pmu_events_map *map)
> +{
> + int rc, event_nr, wanted = get_counterset_start(set) + nr;
> +
> + if (map) {
> + struct pmu_event *evp = map->table;
> +
> + for (; evp->name || evp->event || evp->desc; ++evp) {
> + if (evp->name == NULL || evp->event == NULL)
> + continue;
> + rc = sscanf(evp->event, "event=%x", &event_nr);
> + if (rc == 1 && event_nr == wanted)
> + return evp->name;
> + }
> + }
> + return NULL;
> +}
> +
> static void s390_cpumcfdg_dump(struct perf_sample *sample)
> {
> size_t i, len = sample->raw_size, offset = 0;
> unsigned char *buf = sample->raw_data;
> const char *color = PERF_COLOR_BLUE;
> struct cf_ctrset_entry *cep, ce;
> + struct pmu_events_map *map;
> + struct perf_pmu pmu;
> u64 *p;
>
> + memset(&pmu, 0, sizeof(pmu));
> + map = perf_pmu__find_map(&pmu);
> while (offset < len) {
> cep = (struct cf_ctrset_entry *)(buf + offset);
>
> @@ -135,12 +183,13 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)
>
> color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
> " Counters:%d\n", offset, ce.set, ce.ctr);
> - for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; i += 2, p += 2)
> + for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
> + const char *ev_name = get_counter_name(ce.set, i, map);
> +
> color_fprintf(stdout, color,
> - "\tCounter:%03d Value:%#018lx"
> - " Counter:%03d Value:%#018lx\n",
> - i, be64_to_cpu(*p),
> - i + 1, be64_to_cpu(*(p + 1)));
> + "\tCounter:%03d %s Value:%#018lx\n", i,
> + ev_name ?: "<unknown>", be64_to_cpu(*p));
> + }
> offset += ctrset_size(&ce);
> }
> }
> --
> 2.14.3

--

- Arnaldo

2019-01-17 14:10:40

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCHv2 3/3] perf report: s390 dump counter set data to file.

Em Thu, Jan 17, 2019 at 10:30:03AM +0100, Thomas Richter escreveu:
> Add support for the new s390 PMU device cpum_cf_diag to extract
> the counter set diagnostic data. This data is available as event
> raw data and can be created with this command:

Thanks, applied.

- Arnaldo

> [root@s35lp76 perf]# ./perf record -R -e '{rbd000,rbc000}' --
> ~/mytests/facultaet 2500
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.009 MB perf.data ]
> [root@s35lp76 perf]#
>
> The new event 0xbc000 generated this counter set diagnostic
> trace data. The data can be extracted using command:
>
> [root@s35lp76 perf]# ./perf report --stdio --itrace=d
> #
> # Total Lost Samples: 0
> #
> # Samples: 21 of events 'anon group { rbd000, rbc000 }'
> # Event count (approx.): 21
> #
> # Overhead Command Shared Object Symbol
> # ................ ......... ................. ........................
> #
> 80.95% 0.00% facultaet facultaet [.] facultaet
> 4.76% 0.00% facultaet [kernel.kallsyms] [k] check_chain_key
> 4.76% 0.00% facultaet [kernel.kallsyms] [k] ftrace_likely_update
> 4.76% 0.00% facultaet [kernel.kallsyms] [k] lock_release
> 4.76% 0.00% facultaet libc-2.26.so [.] _dl_addr
> [root@s35lp76 perf]# ll aux*
> -rw-r--r-- 1 root root 3408 Oct 16 12:40 aux.ctr.02
> -rw-r--r-- 1 root root 4096 Oct 16 12:40 aux.smp.02
> [root@s35lp76 perf]#
>
> The files named aux.ctr.## contain the counter set diagnstic
> data and the files named aux.smp.## contain the sampling
> diagnostic data. ## stand for the CPU number the data was
> taken from.
>
> Signed-off-by: Thomas Richter <[email protected]>
> Reviewed-by: Hendrik Brueckner <[email protected]>
> ---
> tools/perf/util/s390-cpumsf.c | 77 ++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 73 insertions(+), 4 deletions(-)
>
> diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
> index 68b2570304ec..835249c77f56 100644
> --- a/tools/perf/util/s390-cpumsf.c
> +++ b/tools/perf/util/s390-cpumsf.c
> @@ -162,6 +162,7 @@
> #include "auxtrace.h"
> #include "s390-cpumsf.h"
> #include "s390-cpumsf-kernel.h"
> +#include "s390-cpumcf-kernel.h"
> #include "config.h"
>
> struct s390_cpumsf {
> @@ -184,8 +185,58 @@ struct s390_cpumsf_queue {
> struct auxtrace_buffer *buffer;
> int cpu;
> FILE *logfile;
> + FILE *logfile_ctr;
> };
>
> +/* Check if the raw data should be dumped to file. If this is the case and
> + * the file to dump to has not been opened for writing, do so.
> + *
> + * Return 0 on success and greater zero on error so processing continues.
> + */
> +static int s390_cpumcf_dumpctr(struct s390_cpumsf *sf,
> + struct perf_sample *sample)
> +{
> + struct s390_cpumsf_queue *sfq;
> + struct auxtrace_queue *q;
> + int rc = 0;
> +
> + if (!sf->use_logfile || sf->queues.nr_queues <= sample->cpu)
> + return rc;
> +
> + q = &sf->queues.queue_array[sample->cpu];
> + sfq = q->priv;
> + if (!sfq) /* Queue not yet allocated */
> + return rc;
> +
> + if (!sfq->logfile_ctr) {
> + char *name;
> +
> + rc = (sf->logdir)
> + ? asprintf(&name, "%s/aux.ctr.%02x",
> + sf->logdir, sample->cpu)
> + : asprintf(&name, "aux.ctr.%02x", sample->cpu);
> + if (rc > 0)
> + sfq->logfile_ctr = fopen(name, "w");
> + if (sfq->logfile_ctr == NULL) {
> + pr_err("Failed to open counter set log file %s, "
> + "continue...\n", name);
> + rc = 1;
> + }
> + free(name);
> + }
> +
> + if (sfq->logfile_ctr) {
> + /* See comment above for -4 */
> + size_t n = fwrite(sample->raw_data, sample->raw_size - 4, 1,
> + sfq->logfile_ctr);
> + if (n != 1) {
> + pr_err("Failed to write counter set data\n");
> + rc = 1;
> + }
> + }
> + return rc;
> +}
> +
> /* 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)
> @@ -792,7 +843,7 @@ static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample)
> }
>
> static int
> -s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
> +s390_cpumsf_process_event(struct perf_session *session,
> union perf_event *event,
> struct perf_sample *sample,
> struct perf_tool *tool)
> @@ -801,6 +852,8 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
> struct s390_cpumsf,
> auxtrace);
> u64 timestamp = sample->time;
> + struct perf_evsel *ev_bc000;
> +
> int err = 0;
>
> if (dump_trace)
> @@ -811,6 +864,16 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
> return -EINVAL;
> }
>
> + if (event->header.type == PERF_RECORD_SAMPLE &&
> + sample->raw_size) {
> + /* Handle event with raw data */
> + ev_bc000 = perf_evlist__event2evsel(session->evlist, event);
> + if (ev_bc000 &&
> + ev_bc000->attr.config == PERF_EVENT_CPUM_CF_DIAG)
> + err = s390_cpumcf_dumpctr(sf, sample);
> + return err;
> + }
> +
> if (event->header.type == PERF_RECORD_AUX &&
> event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
> return s390_cpumsf_lost(sf, sample);
> @@ -891,9 +954,15 @@ static void s390_cpumsf_free_queues(struct perf_session *session)
> struct s390_cpumsf_queue *sfq = (struct s390_cpumsf_queue *)
> queues->queue_array[i].priv;
>
> - if (sfq != NULL && sfq->logfile) {
> - fclose(sfq->logfile);
> - sfq->logfile = NULL;
> + if (sfq != NULL) {
> + if (sfq->logfile) {
> + fclose(sfq->logfile);
> + sfq->logfile = NULL;
> + }
> + if (sfq->logfile_ctr) {
> + fclose(sfq->logfile_ctr);
> + sfq->logfile_ctr = NULL;
> + }
> }
> zfree(&queues->queue_array[i].priv);
> }
> --
> 2.14.3

--

- Arnaldo

2019-01-17 14:25:08

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

Em Thu, Jan 17, 2019 at 10:30:01AM +0100, Thomas Richter escreveu:
> On s390 the event bc000 (also named CF_DIAG)
> extracts the CPU Measurement Facility diagnostic counter sets
> and displays them as counter number and counter value
> pairs sorted by counter set number.

Thanks for taking my comments into account, I did some changes,
documented in the updated patch, that is at the end of this message,
first my changes to your patch, the end result should be the same:

$ interdiff /wb/thomas.patch /wb/acme.patch
diff -u b/tools/perf/util/Build b/tools/perf/util/Build
--- b/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -44,7 +44,6 @@
libperf-y += map.o
libperf-y += pstack.o
libperf-y += session.o
-libperf-y += trace-event-sample-raw.o
libperf-y += s390-sample-raw.o
libperf-$(CONFIG_TRACE) += syscalltbl.o
libperf-y += ordered-events.o
diff -u b/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
--- b/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -150,8 +150,8 @@
* its raw data.
* The function is only invoked when the dump flag -D is set.
*/
-void s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
- struct perf_sample *sample)
+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample)
{
struct perf_evsel *ev_bc000;

diff -u b/tools/perf/util/session.c b/tools/perf/util/session.c
--- b/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1065,8 +1065,8 @@
file_offset, event->header.size, event->header.type);

trace_event(event);
- if (event->header.type == PERF_RECORD_SAMPLE)
- trace_event_sample_raw(evlist, event, sample);
+ if (event->header.type == PERF_RECORD_SAMPLE && evlist->trace_event_sample_raw)
+ evlist->trace_event_sample_raw(evlist, event, sample);

if (sample)
perf_evlist__print_tstamp(evlist, event, sample);
reverted:
--- b/tools/perf/util/session.h
+++ a/tools/perf/util/session.h
@@ -128,9 +128,4 @@
struct perf_evlist *evlist,
struct machine *machine);

-void trace_event_sample_raw(struct perf_evlist *evlist __maybe_unused,
- union perf_event *event __maybe_unused,
- struct perf_sample *sample __maybe_unused);
-void s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
- struct perf_sample *sample);
#endif /* __PERF_SESSION_H */
reverted:
--- b/tools/perf/util/trace-event-sample-raw.c
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright IBM Corp. 2019
- * Author(s): Thomas Richter <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License (version 2 only)
- * as published by the Free Software Foundation.
- *
- * Architecture specific trace_event function. Save event's bc000 raw data
- * to file. File name is aux.ctr.## where ## stands for the CPU number the
- * sample was taken from.
- */
-
-#include <string.h>
-
-#include "session.h"
-#include "evlist.h"
-
-/* Check platform the perf data file was created on and perform platform
- * specific interpretation.
- */
-void trace_event_sample_raw(struct perf_evlist *evlist, union perf_event *event,
- struct perf_sample *sample)
-{
- const char *arch_pf = perf_env__arch(evlist->env);
-
- if (arch_pf && !strcmp("s390", arch_pf))
- s390_sample_raw(evlist, event, sample);
-}
only in patch2:
unchanged:
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -41,6 +41,18 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)

+/*
+ * Check platform the perf data file was created on and perform platform
+ * specific interpretation.
+ */
+static void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist)
+{
+ const char *arch_pf = perf_env__arch(evlist->env);
+
+ if (arch_pf && !strcmp("s390", arch_pf))
+ evlist->trace_event_sample_raw = perf_evlist__s390_sample_raw;
+}
+
void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
struct thread_map *threads)
{
@@ -53,6 +65,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
fdarray__init(&evlist->pollfd, 64);
evlist->workload.pid = -1;
evlist->bkw_mmap_state = BKW_MMAP_NOTREADY;
+ perf_evlist__init_trace_event_sample_raw(evlist);
}

struct perf_evlist *perf_evlist__new(void)
only in patch2:
unchanged:
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -49,6 +49,9 @@ struct perf_evlist {
struct perf_evsel *selected;
struct events_stats stats;
struct perf_env *env;
+ void (*trace_event_sample_raw)(struct perf_evlist *evlist,
+ union perf_event *event,
+ struct perf_sample *sample);
u64 first_sample_time;
u64 last_sample_time;
};
@@ -315,4 +318,6 @@ void perf_evlist__force_leader(struct perf_evlist *evlist);
struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist,
struct perf_evsel *evsel);

+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample);
#endif /* __PERF_EVLIST_H */
only in patch2:
unchanged:
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -25,6 +25,7 @@ util/parse-branch-options.c
util/rblist.c
util/counts.c
util/print_binary.c
+util/s390-sample-raw.c
util/strlist.c
util/trace-event.c
../lib/rbtree.c



---------------------------------------

And the updated patch:

$ cat /wb/acme.patch
commit b7dd95b7479ed6773c6dbec72e0b867a1cfd3765
Author: Thomas Richter <[email protected]>
Date: Thu Jan 17 10:37:17 2019 -0300

erf report: Display arch specific diagnostic counter sets, starting with s390

On s390 the event bc000 (also named CF_DIAG) extracts the CPU
Measurement Facility diagnostic counter sets and displays them as
counter number and counter value pairs sorted by counter set number.

Output:
[root@s35lp76 perf]# ./perf report -D --stdio

[00000000] Counterset:0 Counters:6
Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000
Counter:002 Value:000000000000000000 Counter:003 Value:000000000000000000
Counter:004 Value:000000000000000000 Counter:005 Value:000000000000000000
Counter:006 Value:000000000000000000 Counter:007 Value:000000000000000000
Counter:008 Value:000000000000000000 Counter:009 Value:000000000000000000
Counter:010 Value:000000000000000000 Counter:011 Value:000000000000000000
Counter:012 Value:000000000000000000 Counter:013 Value:000000000000000000
Counter:014 Value:000000000000000000 Counter:015 Value:000000000000000000
[0x0000d8] Counterset:3 Counters:128
Counter:000 Value:0x000000000000020f Counter:001 Value:0x00000000000001d8
Counter:002 Value:0x000000000000d7fa Counter:003 Value:0x000000000000008b
...

The number in brackets is the offset into the raw data field of the
sample.

New functions trace_event_sample_raw__init() and s390_sample_raw() are
introduced in the code path to enable interpretation on non s390
platforms. This event bc000 attached raw data is generated only on s390
platform. Correct display on other platforms requires correct endianness
handling.

Committer notes:

Added a init function that sets up a evlist function pointer to avoid
repeated tests on evlist->env and calls to perf_env__name() that
involves normalizing, etc, for each PERF_RECORD_SAMPLE.

Removed needless __maybe_unused from the trace_event_raw()
prototype in session.h, move it to be an static function in evlist.

Reviewed-by: Hendrik Brueckner <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Signed-off-by: Thomas Richter <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index af72be7f5b3b..5ff0087ba693 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -44,6 +44,7 @@ libperf-y += machine.o
libperf-y += map.o
libperf-y += pstack.o
libperf-y += session.o
+libperf-y += s390-sample-raw.o
libperf-$(CONFIG_TRACE) += syscalltbl.o
libperf-y += ordered-events.o
libperf-y += namespaces.o
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8c902276d4b4..5f01bced3116 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -41,6 +41,18 @@ int sigqueue(pid_t pid, int sig, const union sigval value);
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)

+/*
+ * Check platform the perf data file was created on and perform platform
+ * specific interpretation.
+ */
+static void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist)
+{
+ const char *arch_pf = perf_env__arch(evlist->env);
+
+ if (arch_pf && !strcmp("s390", arch_pf))
+ evlist->trace_event_sample_raw = perf_evlist__s390_sample_raw;
+}
+
void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
struct thread_map *threads)
{
@@ -53,6 +65,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
fdarray__init(&evlist->pollfd, 64);
evlist->workload.pid = -1;
evlist->bkw_mmap_state = BKW_MMAP_NOTREADY;
+ perf_evlist__init_trace_event_sample_raw(evlist);
}

struct perf_evlist *perf_evlist__new(void)
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 868294491194..18365b1f80b0 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -49,6 +49,9 @@ struct perf_evlist {
struct perf_evsel *selected;
struct events_stats stats;
struct perf_env *env;
+ void (*trace_event_sample_raw)(struct perf_evlist *evlist,
+ union perf_event *event,
+ struct perf_sample *sample);
u64 first_sample_time;
u64 last_sample_time;
};
@@ -315,4 +318,6 @@ void perf_evlist__force_leader(struct perf_evlist *evlist);
struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist,
struct perf_evsel *evsel);

+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample);
#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 7aa0ea64544e..aada3e69565b 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -25,6 +25,7 @@ util/parse-branch-options.c
util/rblist.c
util/counts.c
util/print_binary.c
+util/s390-sample-raw.c
util/strlist.c
util/trace-event.c
../lib/rbtree.c
diff --git a/tools/perf/util/s390-cpumcf-kernel.h b/tools/perf/util/s390-cpumcf-kernel.h
new file mode 100644
index 000000000000..d4356030b504
--- /dev/null
+++ b/tools/perf/util/s390-cpumcf-kernel.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for s390 CPU measurement counter set diagnostic facility
+ *
+ * Copyright IBM Corp. 2019
+ Author(s): Hendrik Brueckner <[email protected]>
+ * Thomas Richter <[email protected]>
+ */
+#ifndef S390_CPUMCF_KERNEL_H
+#define S390_CPUMCF_KERNEL_H
+
+#define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */
+#define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */
+
+struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int set:16; /* 16-23 Counter set identifier */
+ unsigned int ctr:16; /* 24-39 Number of stored counters */
+ unsigned int res1:16; /* 40-63 Reserved */
+};
+
+struct cf_trailer_entry { /* CPU-M CF trailer for raw traces (64 byte) */
+ /* 0 - 7 */
+ union {
+ struct {
+ unsigned int clock_base:1; /* TOD clock base */
+ unsigned int speed:1; /* CPU speed */
+ /* Measurement alerts */
+ unsigned int mtda:1; /* Loss of MT ctr. data alert */
+ unsigned int caca:1; /* Counter auth. change alert */
+ unsigned int lcda:1; /* Loss of counter data alert */
+ };
+ unsigned long flags; /* 0-63 All indicators */
+ };
+ /* 8 - 15 */
+ unsigned int cfvn:16; /* 64-79 Ctr First Version */
+ unsigned int csvn:16; /* 80-95 Ctr Second Version */
+ unsigned int cpu_speed:32; /* 96-127 CPU speed */
+ /* 16 - 23 */
+ unsigned long timestamp; /* 128-191 Timestamp (TOD) */
+ /* 24 - 55 */
+ union {
+ struct {
+ unsigned long progusage1;
+ unsigned long progusage2;
+ unsigned long progusage3;
+ unsigned long tod_base;
+ };
+ unsigned long progusage[4];
+ };
+ /* 56 - 63 */
+ unsigned int mach_type:16; /* Machine type */
+ unsigned int res1:16; /* Reserved */
+ unsigned int res2:32; /* Reserved */
+};
+
+#define CPUMF_CTR_SET_BASIC 0 /* Basic Counter Set */
+#define CPUMF_CTR_SET_USER 1 /* Problem-State Counter Set */
+#define CPUMF_CTR_SET_CRYPTO 2 /* Crypto-Activity Counter Set */
+#define CPUMF_CTR_SET_EXT 3 /* Extended Counter Set */
+#define CPUMF_CTR_SET_MT_DIAG 4 /* MT-diagnostic Counter Set */
+#endif
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
new file mode 100644
index 000000000000..05871da374b6
--- /dev/null
+++ b/tools/perf/util/s390-sample-raw.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2019
+ * Author(s): Thomas Richter <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Architecture specific trace_event function. Save event's bc000 raw data
+ * to file. File name is aux.ctr.## where ## stands for the CPU number the
+ * sample was taken from.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <sys/stat.h>
+#include <asm/byteorder.h>
+
+#include "debug.h"
+#include "util.h"
+#include "auxtrace.h"
+#include "session.h"
+#include "evlist.h"
+#include "config.h"
+#include "color.h"
+#include "s390-cpumcf-kernel.h"
+
+static size_t ctrset_size(struct cf_ctrset_entry *set)
+{
+ return sizeof(*set) + set->ctr * sizeof(u64);
+}
+
+static bool ctrset_valid(struct cf_ctrset_entry *set)
+{
+ return set->def == S390_CPUMCF_DIAG_DEF;
+}
+
+/* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte
+ * aligned and might have trailing padding bytes.
+ * Display the raw data on screen.
+ */
+static bool s390_cpumcfdg_testctr(struct perf_sample *sample)
+{
+ size_t len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ struct cf_trailer_entry *te;
+ struct cf_ctrset_entry *cep, ce;
+
+ if (!len)
+ return false;
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) {
+ /* Raw data for counter sets are always multiple of 8
+ * bytes. Prepending a 4 bytes size field to the
+ * raw data block in the sample causes the perf tool
+ * to append 4 padding bytes to make the raw data part
+ * of the sample a multiple of eight bytes again.
+ *
+ * If the last entry (trailer) is 4 bytes off the raw
+ * area data end, all is good.
+ */
+ if (len - offset - sizeof(*te) == 4)
+ break;
+ pr_err("Invalid counter set entry at %#" PRIx64 "\n",
+ offset);
+ return false;
+ }
+ offset += ctrset_size(&ce);
+ }
+ return true;
+}
+
+/* Dump event bc000 on screen, already tested on correctness. */
+static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,
+ struct cf_trailer_entry *tep)
+{
+ struct cf_trailer_entry te;
+
+ te.flags = be64_to_cpu(tep->flags);
+ te.cfvn = be16_to_cpu(tep->cfvn);
+ te.csvn = be16_to_cpu(tep->csvn);
+ te.cpu_speed = be32_to_cpu(tep->cpu_speed);
+ te.timestamp = be64_to_cpu(tep->timestamp);
+ te.progusage1 = be64_to_cpu(tep->progusage1);
+ te.progusage2 = be64_to_cpu(tep->progusage2);
+ te.progusage3 = be64_to_cpu(tep->progusage3);
+ te.tod_base = be64_to_cpu(tep->tod_base);
+ te.mach_type = be16_to_cpu(tep->mach_type);
+ te.res1 = be16_to_cpu(tep->res1);
+ te.res2 = be32_to_cpu(tep->res2);
+
+ color_fprintf(stdout, color, " [%#08zx] Trailer:%c%c%c%c%c"
+ " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n",
+ offset, te.clock_base ? 'T' : ' ',
+ te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ',
+ te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ',
+ te.cfvn, te.csvn, te.cpu_speed, te.timestamp);
+ color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx"
+ " Type:%x\n\n",
+ te.progusage1, te.progusage2, te.progusage3,
+ te.tod_base, te.mach_type);
+}
+
+static void s390_cpumcfdg_dump(struct perf_sample *sample)
+{
+ size_t i, len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ const char *color = PERF_COLOR_BLUE;
+ struct cf_ctrset_entry *cep, ce;
+ u64 *p;
+
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce)) { /* Print trailer */
+ s390_cpumcfdg_dumptrail(color, offset,
+ (struct cf_trailer_entry *)cep);
+ return;
+ }
+
+ color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
+ " Counters:%d\n", offset, ce.set, ce.ctr);
+ for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; i += 2, p += 2)
+ color_fprintf(stdout, color,
+ "\tCounter:%03d Value:%#018lx"
+ " Counter:%03d Value:%#018lx\n",
+ i, be64_to_cpu(*p),
+ i + 1, be64_to_cpu(*(p + 1)));
+ offset += ctrset_size(&ce);
+ }
+}
+
+/* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events
+ * and if the event was triggered by a counter set diagnostic event display
+ * its raw data.
+ * The function is only invoked when the dump flag -D is set.
+ */
+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample)
+{
+ struct perf_evsel *ev_bc000;
+
+ if (event->header.type != PERF_RECORD_SAMPLE)
+ return;
+
+ ev_bc000 = perf_evlist__event2evsel(evlist, event);
+ if (ev_bc000 == NULL ||
+ ev_bc000->attr.config != PERF_EVENT_CPUM_CF_DIAG)
+ return;
+
+ /* Display raw data on screen */
+ if (!s390_cpumcfdg_testctr(sample)) {
+ pr_err("Invalid counter set data encountered\n");
+ return;
+ }
+ s390_cpumcfdg_dump(sample);
+}
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index d6f41611f504..379a54702ba9 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1065,6 +1065,8 @@ static void dump_event(struct perf_evlist *evlist, union perf_event *event,
file_offset, event->header.size, event->header.type);

trace_event(event);
+ if (event->header.type == PERF_RECORD_SAMPLE && evlist->trace_event_sample_raw)
+ evlist->trace_event_sample_raw(evlist, event, sample);

if (sample)
perf_evlist__print_tstamp(evlist, event, sample);

2019-01-18 08:42:33

by Thomas Richter

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

On 01/17/2019 03:00 PM, Arnaldo Carvalho de Melo wrote:
> erf report: Display arch specific diagnostic counter sets, starting with s390
>
> On s390 the event bc000 (also named CF_DIAG) extracts the CPU
> Measurement Facility diagnostic counter sets and displays them as
> counter number and counter value pairs sorted by counter set number.
>
> Output:
> [root@s35lp76 perf]# ./perf report -D --stdio
>
> [00000000] Counterset:0 Counters:6
> Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
> Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
> Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
> [0x000038] Counterset:1 Counters:2
> Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
> [0x000050] Counterset:2 Counters:16
> Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000
> Counter:002 Value:000000000000000000 Counter:003 Value:000000000000000000
> Counter:004 Value:000000000000000000 Counter:005 Value:000000000000000000
> Counter:006 Value:000000000000000000 Counter:007 Value:000000000000000000
> Counter:008 Value:000000000000000000 Counter:009 Value:000000000000000000
> Counter:010 Value:000000000000000000 Counter:011 Value:000000000000000000
> Counter:012 Value:000000000000000000 Counter:013 Value:000000000000000000
> Counter:014 Value:000000000000000000 Counter:015 Value:000000000000000000
> [0x0000d8] Counterset:3 Counters:128
> Counter:000 Value:0x000000000000020f Counter:001 Value:0x00000000000001d8
> Counter:002 Value:0x000000000000d7fa Counter:003 Value:0x000000000000008b
> ...
>
> The number in brackets is the offset into the raw data field of the
> sample.
>
> New functions trace_event_sample_raw__init() and s390_sample_raw() are
> introduced in the code path to enable interpretation on non s390
> platforms. This event bc000 attached raw data is generated only on s390
> platform. Correct display on other platforms requires correct endianness
> handling.
>
> Committer notes:
>
> Added a init function that sets up a evlist function pointer to avoid
> repeated tests on evlist->env and calls to perf_env__name() that
> involves normalizing, etc, for each PERF_RECORD_SAMPLE.
>
> Removed needless __maybe_unused from the trace_event_raw()
> prototype in session.h, move it to be an static function in evlist.
>
> Reviewed-by: Hendrik Brueckner <[email protected]>

I have applied your changed patch. Works great. Thanks a lot.

Tested-by: Thomas Richter <[email protected]>

--
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


2019-01-20 18:33:33

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

On Thu, Jan 17, 2019 at 11:00:53AM -0300, Arnaldo Carvalho de Melo wrote:

SNIP

> --- a/tools/perf/util/python-ext-sources
> +++ b/tools/perf/util/python-ext-sources
> @@ -25,6 +25,7 @@ util/parse-branch-options.c
> util/rblist.c
> util/counts.c
> util/print_binary.c
> +util/s390-sample-raw.c
> util/strlist.c
> util/trace-event.c
> ../lib/rbtree.c

hi,
this change breaks the python module:

>>> import perf
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: ./perf.so: undefined symbol: color_fprintf

changelog doesn't say anything about python related change

jirka

2019-01-21 14:13:24

by Thomas Richter

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

On 01/21/2019 02:13 PM, Jiri Olsa wrote:
> On Sun, Jan 20, 2019 at 07:18:14PM +0100, Jiri Olsa wrote:
>> On Thu, Jan 17, 2019 at 11:00:53AM -0300, Arnaldo Carvalho de Melo wrote:
>>
>> SNIP
>>
>>> --- a/tools/perf/util/python-ext-sources
>>> +++ b/tools/perf/util/python-ext-sources
>>> @@ -25,6 +25,7 @@ util/parse-branch-options.c
>>> util/rblist.c
>>> util/counts.c
>>> util/print_binary.c
>>> +util/s390-sample-raw.c
>>> util/strlist.c
>>> util/trace-event.c
>>> ../lib/rbtree.c
>>
>> hi,
>> this change breaks the python module:
>>
>> >>> import perf
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in <module>
>> ImportError: ./perf.so: undefined symbol: color_fprintf
>>
>> changelog doesn't say anything about python related change
>
> I made some chenages and movedthat raw sample code
> under s390.. which cured the python module, but
> I haven't tested it on s390.
>
> Could you please check if code in here works for you:
> git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> perf/s390
>
> if it works, I'll post it
>
> thanks,
> jirka
>

I downloaded your repository and checked out branch perf/s390.
It works nicely, you have my tested by:
-
Tested-by: Thomas Richter <[email protected]>

PS: This looks very similar to my version 1 submitted around Jan 11th.
Arnaldo wanted a rework to be able to get these counter values on
non-s390 platforms, that why we came up with version 2(which unfortunately
broke the perf.so python module).

PS2: This was my first encounter to python and I played around a bit
to include the necessary modules to get rid of the undefined warning.
However this ended up in a larger list of C files to include and
stopped at modules
1. util/pmu.c which refers to symbol perf_buf_in which is a FILE pointer
used by some yacc input file.
2. perf_config_bool() which is located in util/config.c and emits a
compile error when included in the util/python-ext-sources file
for python/perf.so module.

So I think this road is a dead end.

Thanks for fixing this.

--
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


2019-01-21 14:19:14

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

Em Mon, Jan 21, 2019 at 02:13:36PM +0100, Jiri Olsa escreveu:
> On Sun, Jan 20, 2019 at 07:18:14PM +0100, Jiri Olsa wrote:
> > On Thu, Jan 17, 2019 at 11:00:53AM -0300, Arnaldo Carvalho de Melo wrote:
> >
> > SNIP
> >
> > > --- a/tools/perf/util/python-ext-sources
> > > +++ b/tools/perf/util/python-ext-sources
> > > @@ -25,6 +25,7 @@ util/parse-branch-options.c
> > > util/rblist.c
> > > util/counts.c
> > > util/print_binary.c
> > > +util/s390-sample-raw.c
> > > util/strlist.c
> > > util/trace-event.c
> > > ../lib/rbtree.c
> >
> > hi,
> > this change breaks the python module:
> >
> > >>> import perf
> > Traceback (most recent call last):
> > File "<stdin>", line 1, in <module>
> > ImportError: ./perf.so: undefined symbol: color_fprintf
> >
> > changelog doesn't say anything about python related change
>
> I made some chenages and movedthat raw sample code
> under s390.. which cured the python module, but
> I haven't tested it on s390.

Nope, I explicitely asked him to build that code for all arches, as we
want to process s390 perf.data files on a x86 or arm or any other arch.

I stumbled on this as well, I think the way to go is to get the
color_fprintf bits in a separate object to avoid dragging more stuff to
the perf binding set of objects and then add that to the python binding.

> Could you please check if code in here works for you:
> git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> perf/s390
>
> if it works, I'll post it
>
> thanks,
> jirka

--

- Arnaldo

2019-01-21 15:24:34

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

On Sun, Jan 20, 2019 at 07:18:14PM +0100, Jiri Olsa wrote:
> On Thu, Jan 17, 2019 at 11:00:53AM -0300, Arnaldo Carvalho de Melo wrote:
>
> SNIP
>
> > --- a/tools/perf/util/python-ext-sources
> > +++ b/tools/perf/util/python-ext-sources
> > @@ -25,6 +25,7 @@ util/parse-branch-options.c
> > util/rblist.c
> > util/counts.c
> > util/print_binary.c
> > +util/s390-sample-raw.c
> > util/strlist.c
> > util/trace-event.c
> > ../lib/rbtree.c
>
> hi,
> this change breaks the python module:
>
> >>> import perf
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> ImportError: ./perf.so: undefined symbol: color_fprintf
>
> changelog doesn't say anything about python related change

I made some chenages and movedthat raw sample code
under s390.. which cured the python module, but
I haven't tested it on s390.

Could you please check if code in here works for you:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/s390

if it works, I'll post it

thanks,
jirka

2019-01-21 18:36:01

by Jiri Olsa

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

On Mon, Jan 21, 2019 at 11:17:48AM -0300, Arnaldo Carvalho de Melo wrote:
> Em Mon, Jan 21, 2019 at 02:13:36PM +0100, Jiri Olsa escreveu:
> > On Sun, Jan 20, 2019 at 07:18:14PM +0100, Jiri Olsa wrote:
> > > On Thu, Jan 17, 2019 at 11:00:53AM -0300, Arnaldo Carvalho de Melo wrote:
> > >
> > > SNIP
> > >
> > > > --- a/tools/perf/util/python-ext-sources
> > > > +++ b/tools/perf/util/python-ext-sources
> > > > @@ -25,6 +25,7 @@ util/parse-branch-options.c
> > > > util/rblist.c
> > > > util/counts.c
> > > > util/print_binary.c
> > > > +util/s390-sample-raw.c
> > > > util/strlist.c
> > > > util/trace-event.c
> > > > ../lib/rbtree.c
> > >
> > > hi,
> > > this change breaks the python module:
> > >
> > > >>> import perf
> > > Traceback (most recent call last):
> > > File "<stdin>", line 1, in <module>
> > > ImportError: ./perf.so: undefined symbol: color_fprintf
> > >
> > > changelog doesn't say anything about python related change
> >
> > I made some chenages and movedthat raw sample code
> > under s390.. which cured the python module, but
> > I haven't tested it on s390.
>
> Nope, I explicitely asked him to build that code for all arches, as we
> want to process s390 perf.data files on a x86 or arm or any other arch.
>

aah, so this actualy works over the s390 perf archive data on x86 host?

I missed that in the original conversation, sry for noise

jirka

> I stumbled on this as well, I think the way to go is to get the
> color_fprintf bits in a separate object to avoid dragging more stuff to
> the perf binding set of objects and then add that to the python binding.
>
> > Could you please check if code in here works for you:
> > git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> > perf/s390
> >
> > if it works, I'll post it
> >
> > thanks,
> > jirka
>
> --
>
> - Arnaldo

2019-01-21 19:19:58

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

Em Mon, Jan 21, 2019 at 11:17:48AM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Mon, Jan 21, 2019 at 02:13:36PM +0100, Jiri Olsa escreveu:
> > On Sun, Jan 20, 2019 at 07:18:14PM +0100, Jiri Olsa wrote:
> > > On Thu, Jan 17, 2019 at 11:00:53AM -0300, Arnaldo Carvalho de Melo wrote:
> > >
> > > SNIP
> > >
> > > > --- a/tools/perf/util/python-ext-sources
> > > > +++ b/tools/perf/util/python-ext-sources
> > > > @@ -25,6 +25,7 @@ util/parse-branch-options.c
> > > > util/rblist.c
> > > > util/counts.c
> > > > util/print_binary.c
> > > > +util/s390-sample-raw.c
> > > > util/strlist.c
> > > > util/trace-event.c
> > > > ../lib/rbtree.c
> > >
> > > hi,
> > > this change breaks the python module:
> > >
> > > >>> import perf
> > > Traceback (most recent call last):
> > > File "<stdin>", line 1, in <module>
> > > ImportError: ./perf.so: undefined symbol: color_fprintf
> > >
> > > changelog doesn't say anything about python related change
> >
> > I made some chenages and movedthat raw sample code
> > under s390.. which cured the python module, but
> > I haven't tested it on s390.
>
> Nope, I explicitely asked him to build that code for all arches, as we
> want to process s390 perf.data files on a x86 or arm or any other arch.
>
> I stumbled on this as well, I think the way to go is to get the
> color_fprintf bits in a separate object to avoid dragging more stuff to
> the perf binding set of objects and then add that to the python binding.

So I changed it so that the init is done in perf_session__new(), and
session.c isn't linked into the python binding, so no need to drag the
s390 specific stuff that drags pmu.c, color.c, etc into the python
binding.

Should be equivalent to the previous patch, but without breaking the
python binding,

- Arnaldo


commit a57dad3354e18f04d0ef198771954c24ad6aed49
Author: Thomas Richter <[email protected]>
Date: Thu Jan 17 10:37:17 2019 -0300

perf report: Display arch specific diagnostic counter sets, starting with s390

On s390 the event bc000 (also named CF_DIAG) extracts the CPU
Measurement Facility diagnostic counter sets and displays them as
counter number and counter value pairs sorted by counter set number.

Output:
[root@s35lp76 perf]# ./perf report -D --stdio

[00000000] Counterset:0 Counters:6
Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000
Counter:002 Value:000000000000000000 Counter:003 Value:000000000000000000
Counter:004 Value:000000000000000000 Counter:005 Value:000000000000000000
Counter:006 Value:000000000000000000 Counter:007 Value:000000000000000000
Counter:008 Value:000000000000000000 Counter:009 Value:000000000000000000
Counter:010 Value:000000000000000000 Counter:011 Value:000000000000000000
Counter:012 Value:000000000000000000 Counter:013 Value:000000000000000000
Counter:014 Value:000000000000000000 Counter:015 Value:000000000000000000
[0x0000d8] Counterset:3 Counters:128
Counter:000 Value:0x000000000000020f Counter:001 Value:0x00000000000001d8
Counter:002 Value:0x000000000000d7fa Counter:003 Value:0x000000000000008b
...

The number in brackets is the offset into the raw data field of the
sample.

New functions trace_event_sample_raw__init() and s390_sample_raw() are
introduced in the code path to enable interpretation on non s390
platforms. This event bc000 attached raw data is generated only on s390
platform. Correct display on other platforms requires correct endianness
handling.

Committer notes:

Added a init function that sets up a evlist function pointer to avoid
repeated tests on evlist->env and calls to perf_env__name() that
involves normalizing, etc, for each PERF_RECORD_SAMPLE.

Removed needless __maybe_unused from the trace_event_raw()
prototype in session.h, move it to be an static function in evlist.

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Link: https://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index af72be7f5b3b..3ad6a800948d 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -44,6 +44,8 @@ libperf-y += machine.o
libperf-y += map.o
libperf-y += pstack.o
libperf-y += session.o
+libperf-y += sample-raw.o
+libperf-y += s390-sample-raw.o
libperf-$(CONFIG_TRACE) += syscalltbl.o
libperf-y += ordered-events.o
libperf-y += namespaces.o
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 868294491194..00ab43c6dd15 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -49,6 +49,9 @@ struct perf_evlist {
struct perf_evsel *selected;
struct events_stats stats;
struct perf_env *env;
+ void (*trace_event_sample_raw)(struct perf_evlist *evlist,
+ union perf_event *event,
+ struct perf_sample *sample);
u64 first_sample_time;
u64 last_sample_time;
};
@@ -314,5 +317,4 @@ void perf_evlist__force_leader(struct perf_evlist *evlist);

struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist,
struct perf_evsel *evsel);
-
#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/s390-cpumcf-kernel.h b/tools/perf/util/s390-cpumcf-kernel.h
new file mode 100644
index 000000000000..d4356030b504
--- /dev/null
+++ b/tools/perf/util/s390-cpumcf-kernel.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for s390 CPU measurement counter set diagnostic facility
+ *
+ * Copyright IBM Corp. 2019
+ Author(s): Hendrik Brueckner <[email protected]>
+ * Thomas Richter <[email protected]>
+ */
+#ifndef S390_CPUMCF_KERNEL_H
+#define S390_CPUMCF_KERNEL_H
+
+#define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */
+#define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */
+
+struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int set:16; /* 16-23 Counter set identifier */
+ unsigned int ctr:16; /* 24-39 Number of stored counters */
+ unsigned int res1:16; /* 40-63 Reserved */
+};
+
+struct cf_trailer_entry { /* CPU-M CF trailer for raw traces (64 byte) */
+ /* 0 - 7 */
+ union {
+ struct {
+ unsigned int clock_base:1; /* TOD clock base */
+ unsigned int speed:1; /* CPU speed */
+ /* Measurement alerts */
+ unsigned int mtda:1; /* Loss of MT ctr. data alert */
+ unsigned int caca:1; /* Counter auth. change alert */
+ unsigned int lcda:1; /* Loss of counter data alert */
+ };
+ unsigned long flags; /* 0-63 All indicators */
+ };
+ /* 8 - 15 */
+ unsigned int cfvn:16; /* 64-79 Ctr First Version */
+ unsigned int csvn:16; /* 80-95 Ctr Second Version */
+ unsigned int cpu_speed:32; /* 96-127 CPU speed */
+ /* 16 - 23 */
+ unsigned long timestamp; /* 128-191 Timestamp (TOD) */
+ /* 24 - 55 */
+ union {
+ struct {
+ unsigned long progusage1;
+ unsigned long progusage2;
+ unsigned long progusage3;
+ unsigned long tod_base;
+ };
+ unsigned long progusage[4];
+ };
+ /* 56 - 63 */
+ unsigned int mach_type:16; /* Machine type */
+ unsigned int res1:16; /* Reserved */
+ unsigned int res2:32; /* Reserved */
+};
+
+#define CPUMF_CTR_SET_BASIC 0 /* Basic Counter Set */
+#define CPUMF_CTR_SET_USER 1 /* Problem-State Counter Set */
+#define CPUMF_CTR_SET_CRYPTO 2 /* Crypto-Activity Counter Set */
+#define CPUMF_CTR_SET_EXT 3 /* Extended Counter Set */
+#define CPUMF_CTR_SET_MT_DIAG 4 /* MT-diagnostic Counter Set */
+#endif
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
new file mode 100644
index 000000000000..7b4879625f01
--- /dev/null
+++ b/tools/perf/util/s390-sample-raw.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2019
+ * Author(s): Thomas Richter <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Architecture specific trace_event function. Save event's bc000 raw data
+ * to file. File name is aux.ctr.## where ## stands for the CPU number the
+ * sample was taken from.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <sys/stat.h>
+#include <asm/byteorder.h>
+
+#include "debug.h"
+#include "util.h"
+#include "auxtrace.h"
+#include "session.h"
+#include "evlist.h"
+#include "config.h"
+#include "color.h"
+#include "sample-raw.h"
+#include "s390-cpumcf-kernel.h"
+
+static size_t ctrset_size(struct cf_ctrset_entry *set)
+{
+ return sizeof(*set) + set->ctr * sizeof(u64);
+}
+
+static bool ctrset_valid(struct cf_ctrset_entry *set)
+{
+ return set->def == S390_CPUMCF_DIAG_DEF;
+}
+
+/* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte
+ * aligned and might have trailing padding bytes.
+ * Display the raw data on screen.
+ */
+static bool s390_cpumcfdg_testctr(struct perf_sample *sample)
+{
+ size_t len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ struct cf_trailer_entry *te;
+ struct cf_ctrset_entry *cep, ce;
+
+ if (!len)
+ return false;
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) {
+ /* Raw data for counter sets are always multiple of 8
+ * bytes. Prepending a 4 bytes size field to the
+ * raw data block in the sample causes the perf tool
+ * to append 4 padding bytes to make the raw data part
+ * of the sample a multiple of eight bytes again.
+ *
+ * If the last entry (trailer) is 4 bytes off the raw
+ * area data end, all is good.
+ */
+ if (len - offset - sizeof(*te) == 4)
+ break;
+ pr_err("Invalid counter set entry at %#" PRIx64 "\n",
+ offset);
+ return false;
+ }
+ offset += ctrset_size(&ce);
+ }
+ return true;
+}
+
+/* Dump event bc000 on screen, already tested on correctness. */
+static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,
+ struct cf_trailer_entry *tep)
+{
+ struct cf_trailer_entry te;
+
+ te.flags = be64_to_cpu(tep->flags);
+ te.cfvn = be16_to_cpu(tep->cfvn);
+ te.csvn = be16_to_cpu(tep->csvn);
+ te.cpu_speed = be32_to_cpu(tep->cpu_speed);
+ te.timestamp = be64_to_cpu(tep->timestamp);
+ te.progusage1 = be64_to_cpu(tep->progusage1);
+ te.progusage2 = be64_to_cpu(tep->progusage2);
+ te.progusage3 = be64_to_cpu(tep->progusage3);
+ te.tod_base = be64_to_cpu(tep->tod_base);
+ te.mach_type = be16_to_cpu(tep->mach_type);
+ te.res1 = be16_to_cpu(tep->res1);
+ te.res2 = be32_to_cpu(tep->res2);
+
+ color_fprintf(stdout, color, " [%#08zx] Trailer:%c%c%c%c%c"
+ " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n",
+ offset, te.clock_base ? 'T' : ' ',
+ te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ',
+ te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ',
+ te.cfvn, te.csvn, te.cpu_speed, te.timestamp);
+ color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx"
+ " Type:%x\n\n",
+ te.progusage1, te.progusage2, te.progusage3,
+ te.tod_base, te.mach_type);
+}
+
+static void s390_cpumcfdg_dump(struct perf_sample *sample)
+{
+ size_t i, len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ const char *color = PERF_COLOR_BLUE;
+ struct cf_ctrset_entry *cep, ce;
+ u64 *p;
+
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce)) { /* Print trailer */
+ s390_cpumcfdg_dumptrail(color, offset,
+ (struct cf_trailer_entry *)cep);
+ return;
+ }
+
+ color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
+ " Counters:%d\n", offset, ce.set, ce.ctr);
+ for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; i += 2, p += 2)
+ color_fprintf(stdout, color,
+ "\tCounter:%03d Value:%#018lx"
+ " Counter:%03d Value:%#018lx\n",
+ i, be64_to_cpu(*p),
+ i + 1, be64_to_cpu(*(p + 1)));
+ offset += ctrset_size(&ce);
+ }
+}
+
+/* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events
+ * and if the event was triggered by a counter set diagnostic event display
+ * its raw data.
+ * The function is only invoked when the dump flag -D is set.
+ */
+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample)
+{
+ struct perf_evsel *ev_bc000;
+
+ if (event->header.type != PERF_RECORD_SAMPLE)
+ return;
+
+ ev_bc000 = perf_evlist__event2evsel(evlist, event);
+ if (ev_bc000 == NULL ||
+ ev_bc000->attr.config != PERF_EVENT_CPUM_CF_DIAG)
+ return;
+
+ /* Display raw data on screen */
+ if (!s390_cpumcfdg_testctr(sample)) {
+ pr_err("Invalid counter set data encountered\n");
+ return;
+ }
+ s390_cpumcfdg_dump(sample);
+}
diff --git a/tools/perf/util/sample-raw.c b/tools/perf/util/sample-raw.c
new file mode 100644
index 000000000000..c21e1311fb0f
--- /dev/null
+++ b/tools/perf/util/sample-raw.c
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <string.h>
+#include "evlist.h"
+#include "env.h"
+#include "sample-raw.h"
+
+/*
+ * Check platform the perf data file was created on and perform platform
+ * specific interpretation.
+ */
+void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist)
+{
+ const char *arch_pf = perf_env__arch(evlist->env);
+
+ if (arch_pf && !strcmp("s390", arch_pf))
+ evlist->trace_event_sample_raw = perf_evlist__s390_sample_raw;
+}
diff --git a/tools/perf/util/sample-raw.h b/tools/perf/util/sample-raw.h
new file mode 100644
index 000000000000..95d445c87e93
--- /dev/null
+++ b/tools/perf/util/sample-raw.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __SAMPLE_RAW_H
+#define __SAMPLE_RAW_H 1
+
+struct perf_evlist;
+union perf_event;
+struct perf_sample;
+
+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist,
+ union perf_event *event,
+ struct perf_sample *sample);
+
+void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist);
+#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index d6f41611f504..b26bc9c54200 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -23,6 +23,7 @@
#include "auxtrace.h"
#include "thread.h"
#include "thread-stack.h"
+#include "sample-raw.h"
#include "stat.h"
#include "arch/common.h"

@@ -147,6 +148,8 @@ struct perf_session *perf_session__new(struct perf_data *data,
perf_session__set_id_hdr_size(session);
perf_session__set_comm_exec(session);
}
+
+ perf_evlist__init_trace_event_sample_raw(session->evlist);
}
} else {
session->machines.host.env = &perf_env;
@@ -1065,6 +1068,8 @@ static void dump_event(struct perf_evlist *evlist, union perf_event *event,
file_offset, event->header.size, event->header.type);

trace_event(event);
+ if (event->header.type == PERF_RECORD_SAMPLE && evlist->trace_event_sample_raw)
+ evlist->trace_event_sample_raw(evlist, event, sample);

if (sample)
perf_evlist__print_tstamp(evlist, event, sample);

2019-01-22 00:03:16

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCHv2 1/3] perf report: Display s390 diagnostic counter sets

Em Mon, Jan 21, 2019 at 07:34:37PM +0100, Jiri Olsa escreveu:
> On Mon, Jan 21, 2019 at 11:17:48AM -0300, Arnaldo Carvalho de Melo wrote:
> > Em Mon, Jan 21, 2019 at 02:13:36PM +0100, Jiri Olsa escreveu:
> > > On Sun, Jan 20, 2019 at 07:18:14PM +0100, Jiri Olsa wrote:
> > > > On Thu, Jan 17, 2019 at 11:00:53AM -0300, Arnaldo Carvalho de Melo wrote:
> > > >
> > > > SNIP
> > > >
> > > > > --- a/tools/perf/util/python-ext-sources
> > > > > +++ b/tools/perf/util/python-ext-sources
> > > > > @@ -25,6 +25,7 @@ util/parse-branch-options.c
> > > > > util/rblist.c
> > > > > util/counts.c
> > > > > util/print_binary.c
> > > > > +util/s390-sample-raw.c
> > > > > util/strlist.c
> > > > > util/trace-event.c
> > > > > ../lib/rbtree.c
> > > >
> > > > hi,
> > > > this change breaks the python module:
> > > >
> > > > >>> import perf
> > > > Traceback (most recent call last):
> > > > File "<stdin>", line 1, in <module>
> > > > ImportError: ./perf.so: undefined symbol: color_fprintf
> > > >
> > > > changelog doesn't say anything about python related change
> > >
> > > I made some chenages and movedthat raw sample code
> > > under s390.. which cured the python module, but
> > > I haven't tested it on s390.
> >
> > Nope, I explicitely asked him to build that code for all arches, as we
> > want to process s390 perf.data files on a x86 or arm or any other arch.
> >
>
> aah, so this actualy works over the s390 perf archive data on x86 host?
>
> I missed that in the original conversation, sry for noise

np, I fixed my mistake by making this be done on perf_session__new(),
right after creating the evlist, this way these arch specific bits,
needed only for dumping the raw sample, do not get dragged via evlist.c
into the perf binding :-)

- Arnaldo

> jirka
>
> > I stumbled on this as well, I think the way to go is to get the
> > color_fprintf bits in a separate object to avoid dragging more stuff to
> > the perf binding set of objects and then add that to the python binding.
> >
> > > Could you please check if code in here works for you:
> > > git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
> > > perf/s390
> > >
> > > if it works, I'll post it
> > >
> > > thanks,
> > > jirka
> >
> > --
> >
> > - Arnaldo

--

- Arnaldo

Subject: [tip:perf/core] perf report: Display names in s390 diagnostic counter sets

Commit-ID: 3e4a1c536b2690cf461e930485b0ab0cdafba73b
Gitweb: https://git.kernel.org/tip/3e4a1c536b2690cf461e930485b0ab0cdafba73b
Author: Thomas Richter <[email protected]>
AuthorDate: Thu, 17 Jan 2019 10:30:02 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 21 Jan 2019 17:00:56 -0300

perf report: Display names in s390 diagnostic counter sets

On s390 the CPU Measurement Facility diagnostic counter sets are
displayed by counter number and value. Add the logical counter name in
the output (if it is available). Otherwise "unknown" is shown.

Output before:

[root@s35lp76 perf]# ./perf report -D --stdio
[00000000] Counterset:0 Counters:6
Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000

Output after:

[root@s35lp76 perf]# ./perf report -D --stdio

[00000000] Counterset:0 Counters:6
Counter:000 cpu_cycles Value:0x000000000085ec36
Counter:001 instructions Value:0x0000000000796c94
Counter:002 l1i_dir_writes Value:0x0000000000005ada
Counter:003 l1i_penalty_cycles Value:0x0000000000092460
Counter:004 l1d_dir_writes Value:0x0000000000006073
Counter:005 l1d_penalty_cycles Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 problem_state_cpu_cycles Value:0x000000000007c59f
Counter:001 problem_state_instructions Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 prng_functions Value:000000000000000000

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]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/s390-sample-raw.c | 59 +++++++++++++++++++++++++++++++++++----
1 file changed, 54 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
index 1c5a4d63bc9d..6650f599ed9c 100644
--- a/tools/perf/util/s390-sample-raw.c
+++ b/tools/perf/util/s390-sample-raw.c
@@ -30,6 +30,7 @@
#include "color.h"
#include "sample-raw.h"
#include "s390-cpumcf-kernel.h"
+#include "pmu-events/pmu-events.h"

static size_t ctrset_size(struct cf_ctrset_entry *set)
{
@@ -112,14 +113,61 @@ static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,
te.tod_base, te.mach_type);
}

+/* Return starting number of a counter set */
+static int get_counterset_start(int setnr)
+{
+ switch (setnr) {
+ case CPUMF_CTR_SET_BASIC: /* Basic counter set */
+ return 0;
+ case CPUMF_CTR_SET_USER: /* Problem state counter set */
+ return 32;
+ case CPUMF_CTR_SET_CRYPTO: /* Crypto counter set */
+ return 64;
+ case CPUMF_CTR_SET_EXT: /* Extended counter set */
+ return 128;
+ case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */
+ return 448;
+ default:
+ return -1;
+ }
+}
+
+/* Scan the PMU table and extract the logical name of a counter from the
+ * PMU events table. Input is the counter set and counter number with in the
+ * set. Construct the event number and use this as key. If they match return
+ * the name of this counter.
+ * If no match is found a NULL pointer is returned.
+ */
+static const char *get_counter_name(int set, int nr, struct pmu_events_map *map)
+{
+ int rc, event_nr, wanted = get_counterset_start(set) + nr;
+
+ if (map) {
+ struct pmu_event *evp = map->table;
+
+ for (; evp->name || evp->event || evp->desc; ++evp) {
+ if (evp->name == NULL || evp->event == NULL)
+ continue;
+ rc = sscanf(evp->event, "event=%x", &event_nr);
+ if (rc == 1 && event_nr == wanted)
+ return evp->name;
+ }
+ }
+ return NULL;
+}
+
static void s390_cpumcfdg_dump(struct perf_sample *sample)
{
size_t i, len = sample->raw_size, offset = 0;
unsigned char *buf = sample->raw_data;
const char *color = PERF_COLOR_BLUE;
struct cf_ctrset_entry *cep, ce;
+ struct pmu_events_map *map;
+ struct perf_pmu pmu;
u64 *p;

+ memset(&pmu, 0, sizeof(pmu));
+ map = perf_pmu__find_map(&pmu);
while (offset < len) {
cep = (struct cf_ctrset_entry *)(buf + offset);

@@ -136,12 +184,13 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample)

color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
" Counters:%d\n", offset, ce.set, ce.ctr);
- for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; i += 2, p += 2)
+ for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; ++i, ++p) {
+ const char *ev_name = get_counter_name(ce.set, i, map);
+
color_fprintf(stdout, color,
- "\tCounter:%03d Value:%#018lx"
- " Counter:%03d Value:%#018lx\n",
- i, be64_to_cpu(*p),
- i + 1, be64_to_cpu(*(p + 1)));
+ "\tCounter:%03d %s Value:%#018lx\n", i,
+ ev_name ?: "<unknown>", be64_to_cpu(*p));
+ }
offset += ctrset_size(&ce);
}
}

Subject: [tip:perf/core] perf report: Display arch specific diagnostic counter sets, starting with s390

Commit-ID: 93115d32e8666614f3578601a0b7b3f4914509f4
Gitweb: https://git.kernel.org/tip/93115d32e8666614f3578601a0b7b3f4914509f4
Author: Thomas Richter <[email protected]>
AuthorDate: Thu, 17 Jan 2019 10:37:17 -0300
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 21 Jan 2019 17:00:48 -0300

perf report: Display arch specific diagnostic counter sets, starting with s390

On s390 the event bc000 (also named CF_DIAG) extracts the CPU
Measurement Facility diagnostic counter sets and displays them as
counter number and counter value pairs sorted by counter set number.

Output:
[root@s35lp76 perf]# ./perf report -D --stdio

[00000000] Counterset:0 Counters:6
Counter:000 Value:0x000000000085ec36 Counter:001 Value:0x0000000000796c94
Counter:002 Value:0x0000000000005ada Counter:003 Value:0x0000000000092460
Counter:004 Value:0x0000000000006073 Counter:005 Value:0x00000000001a9a73
[0x000038] Counterset:1 Counters:2
Counter:000 Value:0x000000000007c59f Counter:001 Value:0x000000000002fad6
[0x000050] Counterset:2 Counters:16
Counter:000 Value:000000000000000000 Counter:001 Value:000000000000000000
Counter:002 Value:000000000000000000 Counter:003 Value:000000000000000000
Counter:004 Value:000000000000000000 Counter:005 Value:000000000000000000
Counter:006 Value:000000000000000000 Counter:007 Value:000000000000000000
Counter:008 Value:000000000000000000 Counter:009 Value:000000000000000000
Counter:010 Value:000000000000000000 Counter:011 Value:000000000000000000
Counter:012 Value:000000000000000000 Counter:013 Value:000000000000000000
Counter:014 Value:000000000000000000 Counter:015 Value:000000000000000000
[0x0000d8] Counterset:3 Counters:128
Counter:000 Value:0x000000000000020f Counter:001 Value:0x00000000000001d8
Counter:002 Value:0x000000000000d7fa Counter:003 Value:0x000000000000008b
...

The number in brackets is the offset into the raw data field of the
sample.

New functions trace_event_sample_raw__init() and s390_sample_raw() are
introduced in the code path to enable interpretation on non s390
platforms. This event bc000 attached raw data is generated only on s390
platform. Correct display on other platforms requires correct endianness
handling.

Committer notes:

Added a init function that sets up a evlist function pointer to avoid
repeated tests on evlist->env and calls to perf_env__name() that
involves normalizing, etc, for each PERF_RECORD_SAMPLE.

Removed needless __maybe_unused from the trace_event_raw()
prototype in session.h, move it to be an static function in evlist.

The 'offset' variable is a size_t, not an u64, fix it to avoid this on
some arches:

CC /tmp/build/perf/util/s390-sample-raw.o
util/s390-sample-raw.c: In function 's390_cpumcfdg_testctr':
util/s390-sample-raw.c:77:4: error: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'size_t' [-Werror=format=]
pr_err("Invalid counter set entry at %#" PRIx64 "\n",
^
cc1: all warnings being treated as errors

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
Cc: Martin Schwidefsky <[email protected]>
Cc: Heiko Carstens <[email protected]>
Link: https://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/Build | 2 +
tools/perf/util/evlist.h | 4 +-
tools/perf/util/s390-cpumcf-kernel.h | 62 +++++++++++++
tools/perf/util/s390-sample-raw.c | 173 +++++++++++++++++++++++++++++++++++
tools/perf/util/sample-raw.c | 18 ++++
tools/perf/util/sample-raw.h | 14 +++
tools/perf/util/session.c | 5 +
7 files changed, 277 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index af72be7f5b3b..3ad6a800948d 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -44,6 +44,8 @@ libperf-y += machine.o
libperf-y += map.o
libperf-y += pstack.o
libperf-y += session.o
+libperf-y += sample-raw.o
+libperf-y += s390-sample-raw.o
libperf-$(CONFIG_TRACE) += syscalltbl.o
libperf-y += ordered-events.o
libperf-y += namespaces.o
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 868294491194..00ab43c6dd15 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -49,6 +49,9 @@ struct perf_evlist {
struct perf_evsel *selected;
struct events_stats stats;
struct perf_env *env;
+ void (*trace_event_sample_raw)(struct perf_evlist *evlist,
+ union perf_event *event,
+ struct perf_sample *sample);
u64 first_sample_time;
u64 last_sample_time;
};
@@ -314,5 +317,4 @@ void perf_evlist__force_leader(struct perf_evlist *evlist);

struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist,
struct perf_evsel *evsel);
-
#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/s390-cpumcf-kernel.h b/tools/perf/util/s390-cpumcf-kernel.h
new file mode 100644
index 000000000000..d4356030b504
--- /dev/null
+++ b/tools/perf/util/s390-cpumcf-kernel.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for s390 CPU measurement counter set diagnostic facility
+ *
+ * Copyright IBM Corp. 2019
+ Author(s): Hendrik Brueckner <[email protected]>
+ * Thomas Richter <[email protected]>
+ */
+#ifndef S390_CPUMCF_KERNEL_H
+#define S390_CPUMCF_KERNEL_H
+
+#define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */
+#define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */
+
+struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */
+ unsigned int def:16; /* 0-15 Data Entry Format */
+ unsigned int set:16; /* 16-23 Counter set identifier */
+ unsigned int ctr:16; /* 24-39 Number of stored counters */
+ unsigned int res1:16; /* 40-63 Reserved */
+};
+
+struct cf_trailer_entry { /* CPU-M CF trailer for raw traces (64 byte) */
+ /* 0 - 7 */
+ union {
+ struct {
+ unsigned int clock_base:1; /* TOD clock base */
+ unsigned int speed:1; /* CPU speed */
+ /* Measurement alerts */
+ unsigned int mtda:1; /* Loss of MT ctr. data alert */
+ unsigned int caca:1; /* Counter auth. change alert */
+ unsigned int lcda:1; /* Loss of counter data alert */
+ };
+ unsigned long flags; /* 0-63 All indicators */
+ };
+ /* 8 - 15 */
+ unsigned int cfvn:16; /* 64-79 Ctr First Version */
+ unsigned int csvn:16; /* 80-95 Ctr Second Version */
+ unsigned int cpu_speed:32; /* 96-127 CPU speed */
+ /* 16 - 23 */
+ unsigned long timestamp; /* 128-191 Timestamp (TOD) */
+ /* 24 - 55 */
+ union {
+ struct {
+ unsigned long progusage1;
+ unsigned long progusage2;
+ unsigned long progusage3;
+ unsigned long tod_base;
+ };
+ unsigned long progusage[4];
+ };
+ /* 56 - 63 */
+ unsigned int mach_type:16; /* Machine type */
+ unsigned int res1:16; /* Reserved */
+ unsigned int res2:32; /* Reserved */
+};
+
+#define CPUMF_CTR_SET_BASIC 0 /* Basic Counter Set */
+#define CPUMF_CTR_SET_USER 1 /* Problem-State Counter Set */
+#define CPUMF_CTR_SET_CRYPTO 2 /* Crypto-Activity Counter Set */
+#define CPUMF_CTR_SET_EXT 3 /* Extended Counter Set */
+#define CPUMF_CTR_SET_MT_DIAG 4 /* MT-diagnostic Counter Set */
+#endif
diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c
new file mode 100644
index 000000000000..1c5a4d63bc9d
--- /dev/null
+++ b/tools/perf/util/s390-sample-raw.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2019
+ * Author(s): Thomas Richter <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2 only)
+ * as published by the Free Software Foundation.
+ *
+ * Architecture specific trace_event function. Save event's bc000 raw data
+ * to file. File name is aux.ctr.## where ## stands for the CPU number the
+ * sample was taken from.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <sys/stat.h>
+#include <linux/compiler.h>
+#include <asm/byteorder.h>
+
+#include "debug.h"
+#include "util.h"
+#include "auxtrace.h"
+#include "session.h"
+#include "evlist.h"
+#include "config.h"
+#include "color.h"
+#include "sample-raw.h"
+#include "s390-cpumcf-kernel.h"
+
+static size_t ctrset_size(struct cf_ctrset_entry *set)
+{
+ return sizeof(*set) + set->ctr * sizeof(u64);
+}
+
+static bool ctrset_valid(struct cf_ctrset_entry *set)
+{
+ return set->def == S390_CPUMCF_DIAG_DEF;
+}
+
+/* CPU Measurement Counter Facility raw data is a byte stream. It is 8 byte
+ * aligned and might have trailing padding bytes.
+ * Display the raw data on screen.
+ */
+static bool s390_cpumcfdg_testctr(struct perf_sample *sample)
+{
+ size_t len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ struct cf_trailer_entry *te;
+ struct cf_ctrset_entry *cep, ce;
+
+ if (!len)
+ return false;
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce) || offset + ctrset_size(&ce) > len) {
+ /* Raw data for counter sets are always multiple of 8
+ * bytes. Prepending a 4 bytes size field to the
+ * raw data block in the sample causes the perf tool
+ * to append 4 padding bytes to make the raw data part
+ * of the sample a multiple of eight bytes again.
+ *
+ * If the last entry (trailer) is 4 bytes off the raw
+ * area data end, all is good.
+ */
+ if (len - offset - sizeof(*te) == 4)
+ break;
+ pr_err("Invalid counter set entry at %zd\n", offset);
+ return false;
+ }
+ offset += ctrset_size(&ce);
+ }
+ return true;
+}
+
+/* Dump event bc000 on screen, already tested on correctness. */
+static void s390_cpumcfdg_dumptrail(const char *color, size_t offset,
+ struct cf_trailer_entry *tep)
+{
+ struct cf_trailer_entry te;
+
+ te.flags = be64_to_cpu(tep->flags);
+ te.cfvn = be16_to_cpu(tep->cfvn);
+ te.csvn = be16_to_cpu(tep->csvn);
+ te.cpu_speed = be32_to_cpu(tep->cpu_speed);
+ te.timestamp = be64_to_cpu(tep->timestamp);
+ te.progusage1 = be64_to_cpu(tep->progusage1);
+ te.progusage2 = be64_to_cpu(tep->progusage2);
+ te.progusage3 = be64_to_cpu(tep->progusage3);
+ te.tod_base = be64_to_cpu(tep->tod_base);
+ te.mach_type = be16_to_cpu(tep->mach_type);
+ te.res1 = be16_to_cpu(tep->res1);
+ te.res2 = be32_to_cpu(tep->res2);
+
+ color_fprintf(stdout, color, " [%#08zx] Trailer:%c%c%c%c%c"
+ " Cfvn:%d Csvn:%d Speed:%d TOD:%#llx\n",
+ offset, te.clock_base ? 'T' : ' ',
+ te.speed ? 'S' : ' ', te.mtda ? 'M' : ' ',
+ te.caca ? 'C' : ' ', te.lcda ? 'L' : ' ',
+ te.cfvn, te.csvn, te.cpu_speed, te.timestamp);
+ color_fprintf(stdout, color, "\t\t1:%lx 2:%lx 3:%lx TOD-Base:%#llx"
+ " Type:%x\n\n",
+ te.progusage1, te.progusage2, te.progusage3,
+ te.tod_base, te.mach_type);
+}
+
+static void s390_cpumcfdg_dump(struct perf_sample *sample)
+{
+ size_t i, len = sample->raw_size, offset = 0;
+ unsigned char *buf = sample->raw_data;
+ const char *color = PERF_COLOR_BLUE;
+ struct cf_ctrset_entry *cep, ce;
+ u64 *p;
+
+ while (offset < len) {
+ cep = (struct cf_ctrset_entry *)(buf + offset);
+
+ ce.def = be16_to_cpu(cep->def);
+ ce.set = be16_to_cpu(cep->set);
+ ce.ctr = be16_to_cpu(cep->ctr);
+ ce.res1 = be16_to_cpu(cep->res1);
+
+ if (!ctrset_valid(&ce)) { /* Print trailer */
+ s390_cpumcfdg_dumptrail(color, offset,
+ (struct cf_trailer_entry *)cep);
+ return;
+ }
+
+ color_fprintf(stdout, color, " [%#08zx] Counterset:%d"
+ " Counters:%d\n", offset, ce.set, ce.ctr);
+ for (i = 0, p = (u64 *)(cep + 1); i < ce.ctr; i += 2, p += 2)
+ color_fprintf(stdout, color,
+ "\tCounter:%03d Value:%#018lx"
+ " Counter:%03d Value:%#018lx\n",
+ i, be64_to_cpu(*p),
+ i + 1, be64_to_cpu(*(p + 1)));
+ offset += ctrset_size(&ce);
+ }
+}
+
+/* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events
+ * and if the event was triggered by a counter set diagnostic event display
+ * its raw data.
+ * The function is only invoked when the dump flag -D is set.
+ */
+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event,
+ struct perf_sample *sample)
+{
+ struct perf_evsel *ev_bc000;
+
+ if (event->header.type != PERF_RECORD_SAMPLE)
+ return;
+
+ ev_bc000 = perf_evlist__event2evsel(evlist, event);
+ if (ev_bc000 == NULL ||
+ ev_bc000->attr.config != PERF_EVENT_CPUM_CF_DIAG)
+ return;
+
+ /* Display raw data on screen */
+ if (!s390_cpumcfdg_testctr(sample)) {
+ pr_err("Invalid counter set data encountered\n");
+ return;
+ }
+ s390_cpumcfdg_dump(sample);
+}
diff --git a/tools/perf/util/sample-raw.c b/tools/perf/util/sample-raw.c
new file mode 100644
index 000000000000..c21e1311fb0f
--- /dev/null
+++ b/tools/perf/util/sample-raw.c
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <string.h>
+#include "evlist.h"
+#include "env.h"
+#include "sample-raw.h"
+
+/*
+ * Check platform the perf data file was created on and perform platform
+ * specific interpretation.
+ */
+void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist)
+{
+ const char *arch_pf = perf_env__arch(evlist->env);
+
+ if (arch_pf && !strcmp("s390", arch_pf))
+ evlist->trace_event_sample_raw = perf_evlist__s390_sample_raw;
+}
diff --git a/tools/perf/util/sample-raw.h b/tools/perf/util/sample-raw.h
new file mode 100644
index 000000000000..95d445c87e93
--- /dev/null
+++ b/tools/perf/util/sample-raw.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __SAMPLE_RAW_H
+#define __SAMPLE_RAW_H 1
+
+struct perf_evlist;
+union perf_event;
+struct perf_sample;
+
+void perf_evlist__s390_sample_raw(struct perf_evlist *evlist,
+ union perf_event *event,
+ struct perf_sample *sample);
+
+void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist);
+#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index d6f41611f504..b26bc9c54200 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -23,6 +23,7 @@
#include "auxtrace.h"
#include "thread.h"
#include "thread-stack.h"
+#include "sample-raw.h"
#include "stat.h"
#include "arch/common.h"

@@ -147,6 +148,8 @@ struct perf_session *perf_session__new(struct perf_data *data,
perf_session__set_id_hdr_size(session);
perf_session__set_comm_exec(session);
}
+
+ perf_evlist__init_trace_event_sample_raw(session->evlist);
}
} else {
session->machines.host.env = &perf_env;
@@ -1065,6 +1068,8 @@ static void dump_event(struct perf_evlist *evlist, union perf_event *event,
file_offset, event->header.size, event->header.type);

trace_event(event);
+ if (event->header.type == PERF_RECORD_SAMPLE && evlist->trace_event_sample_raw)
+ evlist->trace_event_sample_raw(evlist, event, sample);

if (sample)
perf_evlist__print_tstamp(evlist, event, sample);

Subject: [tip:perf/core] perf report: Dump s390 counter set data to file

Commit-ID: 8dabe9c43af7aa78b16ce0d61bc595eca20c7a70
Gitweb: https://git.kernel.org/tip/8dabe9c43af7aa78b16ce0d61bc595eca20c7a70
Author: Thomas Richter <[email protected]>
AuthorDate: Thu, 17 Jan 2019 10:30:03 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Mon, 21 Jan 2019 17:00:57 -0300

perf report: Dump s390 counter set data to file

Add support for the new s390 PMU device cpum_cf_diag to extract the
counter set diagnostic data. This data is available as event raw data
and can be created with this command:

[root@s35lp76 perf]# ./perf record -R -e '{rbd000,rbc000}' --
~/mytests/facultaet 2500
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.009 MB perf.data ]
[root@s35lp76 perf]#

The new event 0xbc000 generated this counter set diagnostic trace data.
The data can be extracted using command:

[root@s35lp76 perf]# ./perf report --stdio --itrace=d
#
# Total Lost Samples: 0
#
# Samples: 21 of events 'anon group { rbd000, rbc000 }'
# Event count (approx.): 21
#
# Overhead Command Shared Object Symbol
# ................ ......... ................. ........................
#
80.95% 0.00% facultaet facultaet [.] facultaet
4.76% 0.00% facultaet [kernel.kallsyms] [k] check_chain_key
4.76% 0.00% facultaet [kernel.kallsyms] [k] ftrace_likely_update
4.76% 0.00% facultaet [kernel.kallsyms] [k] lock_release
4.76% 0.00% facultaet libc-2.26.so [.] _dl_addr
[root@s35lp76 perf]# ll aux*
-rw-r--r-- 1 root root 3408 Oct 16 12:40 aux.ctr.02
-rw-r--r-- 1 root root 4096 Oct 16 12:40 aux.smp.02
[root@s35lp76 perf]#

The files named aux.ctr.## contain the counter set diagnostic data and
the files named aux.smp.## contain the sampling diagnostic data. ##
stand for the CPU number the data was taken from.

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]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/s390-cpumsf.c | 77 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 73 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c
index 68b2570304ec..835249c77f56 100644
--- a/tools/perf/util/s390-cpumsf.c
+++ b/tools/perf/util/s390-cpumsf.c
@@ -162,6 +162,7 @@
#include "auxtrace.h"
#include "s390-cpumsf.h"
#include "s390-cpumsf-kernel.h"
+#include "s390-cpumcf-kernel.h"
#include "config.h"

struct s390_cpumsf {
@@ -184,8 +185,58 @@ struct s390_cpumsf_queue {
struct auxtrace_buffer *buffer;
int cpu;
FILE *logfile;
+ FILE *logfile_ctr;
};

+/* Check if the raw data should be dumped to file. If this is the case and
+ * the file to dump to has not been opened for writing, do so.
+ *
+ * Return 0 on success and greater zero on error so processing continues.
+ */
+static int s390_cpumcf_dumpctr(struct s390_cpumsf *sf,
+ struct perf_sample *sample)
+{
+ struct s390_cpumsf_queue *sfq;
+ struct auxtrace_queue *q;
+ int rc = 0;
+
+ if (!sf->use_logfile || sf->queues.nr_queues <= sample->cpu)
+ return rc;
+
+ q = &sf->queues.queue_array[sample->cpu];
+ sfq = q->priv;
+ if (!sfq) /* Queue not yet allocated */
+ return rc;
+
+ if (!sfq->logfile_ctr) {
+ char *name;
+
+ rc = (sf->logdir)
+ ? asprintf(&name, "%s/aux.ctr.%02x",
+ sf->logdir, sample->cpu)
+ : asprintf(&name, "aux.ctr.%02x", sample->cpu);
+ if (rc > 0)
+ sfq->logfile_ctr = fopen(name, "w");
+ if (sfq->logfile_ctr == NULL) {
+ pr_err("Failed to open counter set log file %s, "
+ "continue...\n", name);
+ rc = 1;
+ }
+ free(name);
+ }
+
+ if (sfq->logfile_ctr) {
+ /* See comment above for -4 */
+ size_t n = fwrite(sample->raw_data, sample->raw_size - 4, 1,
+ sfq->logfile_ctr);
+ if (n != 1) {
+ pr_err("Failed to write counter set data\n");
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
/* 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)
@@ -792,7 +843,7 @@ static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample)
}

static int
-s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
+s390_cpumsf_process_event(struct perf_session *session,
union perf_event *event,
struct perf_sample *sample,
struct perf_tool *tool)
@@ -801,6 +852,8 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
struct s390_cpumsf,
auxtrace);
u64 timestamp = sample->time;
+ struct perf_evsel *ev_bc000;
+
int err = 0;

if (dump_trace)
@@ -811,6 +864,16 @@ s390_cpumsf_process_event(struct perf_session *session __maybe_unused,
return -EINVAL;
}

+ if (event->header.type == PERF_RECORD_SAMPLE &&
+ sample->raw_size) {
+ /* Handle event with raw data */
+ ev_bc000 = perf_evlist__event2evsel(session->evlist, event);
+ if (ev_bc000 &&
+ ev_bc000->attr.config == PERF_EVENT_CPUM_CF_DIAG)
+ err = s390_cpumcf_dumpctr(sf, sample);
+ return err;
+ }
+
if (event->header.type == PERF_RECORD_AUX &&
event->aux.flags & PERF_AUX_FLAG_TRUNCATED)
return s390_cpumsf_lost(sf, sample);
@@ -891,9 +954,15 @@ static void s390_cpumsf_free_queues(struct perf_session *session)
struct s390_cpumsf_queue *sfq = (struct s390_cpumsf_queue *)
queues->queue_array[i].priv;

- if (sfq != NULL && sfq->logfile) {
- fclose(sfq->logfile);
- sfq->logfile = NULL;
+ if (sfq != NULL) {
+ if (sfq->logfile) {
+ fclose(sfq->logfile);
+ sfq->logfile = NULL;
+ }
+ if (sfq->logfile_ctr) {
+ fclose(sfq->logfile_ctr);
+ sfq->logfile_ctr = NULL;
+ }
}
zfree(&queues->queue_array[i].priv);
}