2018-02-13 15:15:39

by Thomas-Mich Richter

[permalink] [raw]
Subject: [PATCH 1/4] perf record: Provide detailed information on s390 CPU

When perf record ... is setup to record data, the s390
cpu information was a fixed string "IBM/S390".

Replace this string with one containing more information
about the machine. The information included in the cpuid is
a comma separated list:
manufacturer,type,model-capacity,model[,version,authorization]
with

- manufacturer: up to 16 byte name of the manufacturer (IBM).
- type: a four digit number refering to the machine
generation.
- model-capacitiy: up to 16 characters describing number
of cpus etc.
- model: up to 16 characters describing model.
- version: the CPU-MF counter facility version number,
available on LPARs only, omitted on z/VM guests.
- authorization: the CPU-MF counter facility authorization level,
available on LPARs only, omitted on z/VM guests.

Before:
[root@s8360047 perf]# ./perf record -- sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.001 MB perf.data (4 samples) ]
[root@s8360047 perf]# ./perf report --header | fgrep cpuid
# cpuid : IBM/S390
[root@s8360047 perf]#

After:
[root@s35lp76 perf]# ./perf report --header|fgrep cpuid
# cpuid : IBM,3906,704,M03,3.5,002f
[root@s35lp76 perf]#

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

diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
index 9fa6c3e5782c..3d29ba47edce 100644
--- a/tools/perf/arch/s390/util/header.c
+++ b/tools/perf/arch/s390/util/header.c
@@ -1,8 +1,9 @@
/*
* Implementation of get_cpuid().
*
- * Copyright 2014 IBM Corp.
+ * Copyright IBM Corp. 2014, 2018
* Author(s): Alexander Yarygin <[email protected]>
+ * 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)
@@ -13,16 +14,131 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>

#include "../../util/header.h"
+#include "../../util/util.h"
+
+#define SYSINFO_MANU "Manufacturer:"
+#define SYSINFO_TYPE "Type:"
+#define SYSINFO_MODEL "Model:"
+#define SRVLVL_CPUMF "CPU-MF:"
+#define SRVLVL_VERSION "version="
+#define SRVLVL_AUTHORIZATION "authorization="
+#define SYSINFO "/proc/sysinfo"
+#define SRVLVL "/proc/service_levels"

int get_cpuid(char *buffer, size_t sz)
{
- const char *cpuid = "IBM/S390";
+ char *cp, *line = NULL, *line2;
+ char type[8], model[33], version[8], manufacturer[32], authorization[8];
+ int read;
+ unsigned long line_sz;
+ size_t nbytes;
+ FILE *sysinfo;
+
+ /*
+ * Scan /proc/sysinfo line by line and read out values for
+ * Manufacturer:, Type: and Model:, for example:
+ * Manufacturer: IBM
+ * Type: 2964
+ * Model: 702 N96
+ * The first word is the Model Capacity and the second word is
+ * Model (can be omitted). Both words have a maximum size of 16
+ * bytes.
+ */
+ memset(manufacturer, 0, sizeof(manufacturer));
+ memset(type, 0, sizeof(type));
+ memset(model, 0, sizeof(model));
+ memset(version, 0, sizeof(version));
+ memset(authorization, 0, sizeof(authorization));
+
+ sysinfo = fopen(SYSINFO, "r");
+ if (sysinfo == NULL)
+ return -1;
+
+ while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
+ if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) {
+ line2 = line + strlen(SYSINFO_MANU);
+
+ while ((cp = strtok_r(line2, "\n ", &line2)))
+ strncat(manufacturer, cp, sizeof(manufacturer));
+ }
+
+ if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) {
+ line2 = line + strlen(SYSINFO_TYPE);
+
+ while ((cp = strtok_r(line2, "\n ", &line2)))
+ strncat(type, cp, sizeof(type));
+ }
+
+ if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) {
+ line2 = line + strlen(SYSINFO_MODEL);
+
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ if (model[0])
+ strcat(model, ",");
+ if (strlen(model) + strlen(cp) < sizeof(model))
+ strncat(model, cp, strlen(cp));
+ }
+ break;
+ }
+ }
+ fclose(sysinfo);

- if (strlen(cpuid) + 1 > sz)
+ /* Missing manufacturer, type or model information should not happen */
+ if (!manufacturer[0] || !type[0] || !model[0])
return -1;

- strcpy(buffer, cpuid);
- return 0;
+ /*
+ * Scan /proc/service_levels and return the CPU-MF counter facility
+ * version number and authorization level.
+ * Optional, does not exist on z/VM guests.
+ */
+ sysinfo = fopen(SRVLVL, "r");
+ if (sysinfo == NULL)
+ goto skip_sysinfo;
+ while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
+ if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF)))
+ continue;
+
+ line2 = line + strlen(SRVLVL_CPUMF);
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ if (!strncmp(cp, SRVLVL_VERSION,
+ strlen(SRVLVL_VERSION))) {
+ char *sep = strchr(cp, '=');
+
+ strncat(version, sep + 1, sizeof(version));
+ }
+ if (!strncmp(cp, SRVLVL_AUTHORIZATION,
+ strlen(SRVLVL_AUTHORIZATION))) {
+ char *sep = strchr(cp, '=');
+
+ strncat(authorization, sep + 1,
+ sizeof(authorization));
+ }
+ }
+ }
+ fclose(sysinfo);
+
+skip_sysinfo:
+ free(line);
+
+ if (version[0] && authorization[0] )
+ nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s",
+ manufacturer, type, model, version,
+ authorization);
+ else
+ nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type,
+ model);
+ return (nbytes >= sz) ? -1 : 0;
+}
+
+char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
+{
+ char *buf = malloc(128);
+
+ if (buf && get_cpuid(buf, 128) < 0)
+ zfree(&buf);
+ return buf;
}
--
2.14.3



2018-02-13 15:16:09

by Thomas-Mich Richter

[permalink] [raw]
Subject: [PATCH 2/4] perf annotate: Scan cpuid for s390 and save machine type

Scan the cpuid string and extract the type number for later
use.

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/arch/s390/annotate/instructions.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c
index 8c72b44444cb..01df9d8303e1 100644
--- a/tools/perf/arch/s390/annotate/instructions.c
+++ b/tools/perf/arch/s390/annotate/instructions.c
@@ -23,12 +23,37 @@ static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *na
return ops;
}

+static int s390__cpuid_parse(struct arch *arch, char *cpuid)
+{
+ unsigned int family;
+ char model[16], model_c[16], cpumf_v[16], cpumf_a[16];
+ int ret;
+
+ /*
+ * cpuid string format:
+ * "IBM,family,model-capacity,model[,cpum_cf-version,cpum_cf-authorization]"
+ */
+ ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%s", &family, model_c,
+ model, cpumf_v, cpumf_a);
+ if (ret >= 2) {
+ arch->family = family;
+ arch->model = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
+ int err = 0;
+
if (!arch->initialized) {
arch->initialized = true;
arch->associate_instruction_ops = s390__associate_ins_ops;
+ if (cpuid)
+ err = s390__cpuid_parse(arch, cpuid);
}

- return 0;
+ return err;
}
--
2.14.3


2018-02-13 15:16:10

by Thomas-Mich Richter

[permalink] [raw]
Subject: [PATCH 3/4] perf cpuid: Introduce a platform specfic cpuid compare function

The function get_cpuid_str() is called by perf_pmu__getcpuid()
and on s390 returns a complete description of the CPU and its
capabilities, which is a comma separated list.

To map the CPU type with the value defined in the
pmu-events/arch/s390/mapfile.csv, introduce an architecture
specific cpuid compare function named strcmp_cpuid_str()

The currently used regex algorithm is defined as the
weak default and will be used if no platform specific
one is defined. This matches the current behavior.

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/arch/s390/util/header.c | 18 +++++++++++++++
tools/perf/util/header.h | 1 +
tools/perf/util/pmu.c | 47 +++++++++++++++++++++++---------------
3 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
index 3d29ba47edce..90360272ced6 100644
--- a/tools/perf/arch/s390/util/header.c
+++ b/tools/perf/arch/s390/util/header.c
@@ -142,3 +142,21 @@ char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
zfree(&buf);
return buf;
}
+
+/*
+ * Compare the cpuid string returned by get_cpuid() function
+ * with the name generated by the jevents file read from
+ * pmu-events/arch/s390/mapfile.csv.
+ *
+ * Parameter mapcpuid is the cpuid as stored in the
+ * pmu-events/arch/s390/mapfile.csv. This is just the type number.
+ * Parameter cpuid is the cpuid returned by function get_cpuid().
+ */
+int strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
+{
+ char *cp = strchr(cpuid, ',');
+
+ if (cp == NULL)
+ return -1;
+ return strncmp(cp + 1, mapcpuid, strlen(mapcpuid));
+}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index f28aaaa3a440..942bdec6d70d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -174,4 +174,5 @@ int write_padded(struct feat_fd *fd, const void *bf,
int get_cpuid(char *buffer, size_t sz);

char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused);
+int strcmp_cpuid_str(const char *s1, const char *s2);
#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 57e38fdf0b34..1111d5bf15ca 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -576,6 +576,34 @@ char * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
return NULL;
}

+/* Return zero when the cpuid from the mapfile.csv matches the
+ * cpuid string generated on this platform.
+ * Otherwise return non-zero.
+ */
+int __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
+{
+ regex_t re;
+ regmatch_t pmatch[1];
+ int match;
+
+ if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) {
+ /* Warn unable to generate match particular string. */
+ pr_info("Invalid regular expression %s\n", mapcpuid);
+ return 1;
+ }
+
+ match = !regexec(&re, cpuid, 1, pmatch, 0);
+ regfree(&re);
+ if (match) {
+ size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
+
+ /* Verify the entire string matched. */
+ if (match_len == strlen(cpuid))
+ return 0;
+ }
+ return 1;
+}
+
static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
{
char *cpuid;
@@ -610,31 +638,14 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)

i = 0;
for (;;) {
- regex_t re;
- regmatch_t pmatch[1];
- int match;
-
map = &pmu_events_map[i++];
if (!map->table) {
map = NULL;
break;
}

- if (regcomp(&re, map->cpuid, REG_EXTENDED) != 0) {
- /* Warn unable to generate match particular string. */
- pr_info("Invalid regular expression %s\n", map->cpuid);
+ if (!strcmp_cpuid_str(map->cpuid, cpuid))
break;
- }
-
- match = !regexec(&re, cpuid, 1, pmatch, 0);
- regfree(&re);
- if (match) {
- size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
-
- /* Verify the entire string matched. */
- if (match_len == strlen(cpuid))
- break;
- }
}
free(cpuid);
return map;
--
2.14.3


2018-02-13 15:16:49

by Thomas-Mich Richter

[permalink] [raw]
Subject: [PATCH 4/4] perf test: Fix test case 23 for s390 z/VM or KVM guests

On s390 perf can be executed on a LPAR with support
for hardware events (i. e. cycles) or on a z/VM or KVM guest
where no hardware events are supported. In this
environment use software event named cpu-clock
for this test case.

Use the cpuid infrastructure functions to determine
the cpuid on s390 which contains an indication of the
cpu counter facility availability.

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
---
tools/perf/tests/code-reading.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 3bf7b145b826..c7115d369511 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -482,6 +482,34 @@ static void fs_something(void)
}
}

+static const char *do_determine_event(bool excl_kernel)
+{
+ const char *event = excl_kernel ? "cycles:u" : "cycles";
+
+#ifdef __s390x__
+ char cpuid[128], model[16], model_c[16], cpum_cf_v[16];
+ unsigned int family;
+ int ret, cpum_cf_a;
+
+ if (get_cpuid(cpuid, sizeof(cpuid)))
+ goto out_clocks;
+ ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%x", &family, model_c,
+ model, cpum_cf_v, &cpum_cf_a);
+ if (ret != 5) /* Not available */
+ goto out_clocks;
+ if (excl_kernel && (cpum_cf_a & 4))
+ return event;
+ if (!excl_kernel && (cpum_cf_a & 2))
+ return event;
+
+ /* Fall through: missing authorization */
+out_clocks:
+ event = excl_kernel ? "cpu-clock:u" : "cpu-clock";
+
+#endif
+ return event;
+}
+
static void do_something(void)
{
fs_something();
@@ -592,10 +620,7 @@ static int do_test_code_reading(bool try_kcore)

perf_evlist__set_maps(evlist, cpus, threads);

- if (excl_kernel)
- str = "cycles:u";
- else
- str = "cycles";
+ str = do_determine_event(excl_kernel);
pr_debug("Parsing event '%s'\n", str);
ret = parse_events(evlist, str, NULL);
if (ret < 0) {
--
2.14.3


2018-02-15 14:54:57

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 1/4] perf record: Provide detailed information on s390 CPU

Em Tue, Feb 13, 2018 at 04:14:16PM +0100, Thomas Richter escreveu:
> When perf record ... is setup to record data, the s390
> cpu information was a fixed string "IBM/S390".
>
> Replace this string with one containing more information
> about the machine. The information included in the cpuid is
> a comma separated list:
> manufacturer,type,model-capacity,model[,version,authorization]
> with

Thanks, applied 1-4

- Arnaldo

2018-02-16 19:19:29

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 1/4] perf record: Provide detailed information on s390 CPU

Em Tue, Feb 13, 2018 at 04:14:16PM +0100, Thomas Richter escreveu:
> When perf record ... is setup to record data, the s390
> cpu information was a fixed string "IBM/S390".
>
> Replace this string with one containing more information
> about the machine. The information included in the cpuid is
> a comma separated list:
> manufacturer,type,model-capacity,model[,version,authorization]
> with
>
> - manufacturer: up to 16 byte name of the manufacturer (IBM).
> - type: a four digit number refering to the machine
> generation.
> - model-capacitiy: up to 16 characters describing number
> of cpus etc.
> - model: up to 16 characters describing model.
> - version: the CPU-MF counter facility version number,
> available on LPARs only, omitted on z/VM guests.
> - authorization: the CPU-MF counter facility authorization level,
> available on LPARs only, omitted on z/VM guests.
>
> Before:
> [root@s8360047 perf]# ./perf record -- sleep 1
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.001 MB perf.data (4 samples) ]
> [root@s8360047 perf]# ./perf report --header | fgrep cpuid
> # cpuid : IBM/S390
> [root@s8360047 perf]#


49 38.13 ubuntu:16.04-x-s390 : FAIL s390x-linux-gnu-gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609


Humm, this seems to be the one causing this:

LINK /tmp/build/perf/plugin_hrtimer.so
LINK /tmp/build/perf/plugin_kmem.so
In file included from /usr/s390x-linux-gnu/include/string.h:635:0,
from arch/s390/util/header.c:16:
In function 'strncat',
inlined from 'get_cpuid' at arch/s390/util/header.c:65:5:
/usr/s390x-linux-gnu/include/bits/string3.h:156:10: error: call to __builtin___strncat_chk might overflow destination buffer [-Werror]
return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
^
In function 'strncat',
inlined from 'get_cpuid' at arch/s390/util/header.c:72:5:
/usr/s390x-linux-gnu/include/bits/string3.h:156:10: error: call to __builtin___strncat_chk might overflow destination buffer [-Werror]
return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
^
In function 'strncat',
inlined from 'get_cpuid' at arch/s390/util/header.c:111:5:
/usr/s390x-linux-gnu/include/bits/string3.h:156:10: error: call to __builtin___strncat_chk might overflow destination buffer [-Werror]
return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
^
In function 'strncat',
inlined from 'get_cpuid' at arch/s390/util/header.c:117:5:
/usr/s390x-linux-gnu/include/bits/string3.h:156:10: error: call to __builtin___strncat_chk might overflow destination buffer [-Werror]
return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
^
LINK /tmp/build/perf/plugin_kvm.so
MKDIR /tmp/build/perf/arch/s390/util/
LINK /tmp/build/perf/plugin_mac80211.so
CC /tmp/build/perf/arch/s390/util/kvm-stat.o
LINK /tmp/build/perf/plugin_sched_switch.so
cc1: all warnings being treated as errors
mv: cannot stat '/tmp/build/perf/arch/s390/util/.header.o.tmp': No such file or directory
/git/linux/tools/build/Makefile.build:96: recipe for target '/tmp/build/perf/arch/s390/util/header.o' failed
make[6]: *** [/tmp/build/perf/arch/s390/util/header.o] Error 1
make[6]: *** Waiting for unfinished jobs....
LINK /tmp/build/perf/plugin_function.so


> After:
> [root@s35lp76 perf]# ./perf report --header|fgrep cpuid
> # cpuid : IBM,3906,704,M03,3.5,002f
> [root@s35lp76 perf]#
>
> Signed-off-by: Thomas Richter <[email protected]>
> Reviewed-by: Hendrik Brueckner <[email protected]>
> ---
> tools/perf/arch/s390/util/header.c | 126 +++++++++++++++++++++++++++++++++++--
> 1 file changed, 121 insertions(+), 5 deletions(-)
>
> diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
> index 9fa6c3e5782c..3d29ba47edce 100644
> --- a/tools/perf/arch/s390/util/header.c
> +++ b/tools/perf/arch/s390/util/header.c
> @@ -1,8 +1,9 @@
> /*
> * Implementation of get_cpuid().
> *
> - * Copyright 2014 IBM Corp.
> + * Copyright IBM Corp. 2014, 2018
> * Author(s): Alexander Yarygin <[email protected]>
> + * 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)
> @@ -13,16 +14,131 @@
> #include <unistd.h>
> #include <stdio.h>
> #include <string.h>
> +#include <ctype.h>
>
> #include "../../util/header.h"
> +#include "../../util/util.h"
> +
> +#define SYSINFO_MANU "Manufacturer:"
> +#define SYSINFO_TYPE "Type:"
> +#define SYSINFO_MODEL "Model:"
> +#define SRVLVL_CPUMF "CPU-MF:"
> +#define SRVLVL_VERSION "version="
> +#define SRVLVL_AUTHORIZATION "authorization="
> +#define SYSINFO "/proc/sysinfo"
> +#define SRVLVL "/proc/service_levels"
>
> int get_cpuid(char *buffer, size_t sz)
> {
> - const char *cpuid = "IBM/S390";
> + char *cp, *line = NULL, *line2;
> + char type[8], model[33], version[8], manufacturer[32], authorization[8];
> + int read;
> + unsigned long line_sz;
> + size_t nbytes;
> + FILE *sysinfo;
> +
> + /*
> + * Scan /proc/sysinfo line by line and read out values for
> + * Manufacturer:, Type: and Model:, for example:
> + * Manufacturer: IBM
> + * Type: 2964
> + * Model: 702 N96
> + * The first word is the Model Capacity and the second word is
> + * Model (can be omitted). Both words have a maximum size of 16
> + * bytes.
> + */
> + memset(manufacturer, 0, sizeof(manufacturer));
> + memset(type, 0, sizeof(type));
> + memset(model, 0, sizeof(model));
> + memset(version, 0, sizeof(version));
> + memset(authorization, 0, sizeof(authorization));
> +
> + sysinfo = fopen(SYSINFO, "r");
> + if (sysinfo == NULL)
> + return -1;
> +
> + while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
> + if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) {
> + line2 = line + strlen(SYSINFO_MANU);
> +
> + while ((cp = strtok_r(line2, "\n ", &line2)))
> + strncat(manufacturer, cp, sizeof(manufacturer));
> + }
> +
> + if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) {
> + line2 = line + strlen(SYSINFO_TYPE);
> +
> + while ((cp = strtok_r(line2, "\n ", &line2)))
> + strncat(type, cp, sizeof(type));
> + }
> +
> + if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) {
> + line2 = line + strlen(SYSINFO_MODEL);
> +
> + while ((cp = strtok_r(line2, "\n ", &line2))) {
> + if (model[0])
> + strcat(model, ",");
> + if (strlen(model) + strlen(cp) < sizeof(model))
> + strncat(model, cp, strlen(cp));
> + }
> + break;
> + }
> + }
> + fclose(sysinfo);
>
> - if (strlen(cpuid) + 1 > sz)
> + /* Missing manufacturer, type or model information should not happen */
> + if (!manufacturer[0] || !type[0] || !model[0])
> return -1;
>
> - strcpy(buffer, cpuid);
> - return 0;
> + /*
> + * Scan /proc/service_levels and return the CPU-MF counter facility
> + * version number and authorization level.
> + * Optional, does not exist on z/VM guests.
> + */
> + sysinfo = fopen(SRVLVL, "r");
> + if (sysinfo == NULL)
> + goto skip_sysinfo;
> + while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
> + if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF)))
> + continue;
> +
> + line2 = line + strlen(SRVLVL_CPUMF);
> + while ((cp = strtok_r(line2, "\n ", &line2))) {
> + if (!strncmp(cp, SRVLVL_VERSION,
> + strlen(SRVLVL_VERSION))) {
> + char *sep = strchr(cp, '=');
> +
> + strncat(version, sep + 1, sizeof(version));
> + }
> + if (!strncmp(cp, SRVLVL_AUTHORIZATION,
> + strlen(SRVLVL_AUTHORIZATION))) {
> + char *sep = strchr(cp, '=');
> +
> + strncat(authorization, sep + 1,
> + sizeof(authorization));
> + }
> + }
> + }
> + fclose(sysinfo);
> +
> +skip_sysinfo:
> + free(line);
> +
> + if (version[0] && authorization[0] )
> + nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s",
> + manufacturer, type, model, version,
> + authorization);
> + else
> + nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type,
> + model);
> + return (nbytes >= sz) ? -1 : 0;
> +}
> +
> +char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
> +{
> + char *buf = malloc(128);
> +
> + if (buf && get_cpuid(buf, 128) < 0)
> + zfree(&buf);
> + return buf;
> }
> --
> 2.14.3

2018-02-16 19:22:43

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 1/4] perf record: Provide detailed information on s390 CPU

Em Fri, Feb 16, 2018 at 01:55:43PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Tue, Feb 13, 2018 at 04:14:16PM +0100, Thomas Richter escreveu:
>
>
> 49 38.13 ubuntu:16.04-x-s390 : FAIL s390x-linux-gnu-gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
>
>
> Humm, this seems to be the one causing this:
>
> LINK /tmp/build/perf/plugin_hrtimer.so
> LINK /tmp/build/perf/plugin_kmem.so
> In file included from /usr/s390x-linux-gnu/include/string.h:635:0,
> from arch/s390/util/header.c:16:
> In function 'strncat',
> inlined from 'get_cpuid' at arch/s390/util/header.c:65:5:
> /usr/s390x-linux-gnu/include/bits/string3.h:156:10: error: call to __builtin___strncat_chk might overflow destination buffer [-Werror]
> return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));

Ok, now I can build it:

[acme@seventh perf]$ file ../tmp/perf
../tmp/perf: ELF 64-bit MSB shared object, IBM S/390, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, for GNU/Linux 3.2.0, BuildID[sha1]=82a8ff9eb04082acd1630a0f4ff3816d68982eb7, with debug_info, not stripped
[acme@seventh perf]$

With the following patch, using scnprintf (snprintf also has issues),
please try applying this on top of yours and checking that the end
result is sane.

- Arnaldo

diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
index 3d29ba47edce..a78064c25ced 100644
--- a/tools/perf/arch/s390/util/header.c
+++ b/tools/perf/arch/s390/util/header.c
@@ -32,6 +32,7 @@ int get_cpuid(char *buffer, size_t sz)
{
char *cp, *line = NULL, *line2;
char type[8], model[33], version[8], manufacturer[32], authorization[8];
+ int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0;
int read;
unsigned long line_sz;
size_t nbytes;
@@ -61,25 +62,27 @@ int get_cpuid(char *buffer, size_t sz)
if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) {
line2 = line + strlen(SYSINFO_MANU);

- while ((cp = strtok_r(line2, "\n ", &line2)))
- strncat(manufacturer, cp, sizeof(manufacturer));
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ mfsize += scnprintf(manufacturer + mfsize,
+ sizeof(manufacturer) - mfsize, "%s", cp);
+ }
}

if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) {
line2 = line + strlen(SYSINFO_TYPE);

- while ((cp = strtok_r(line2, "\n ", &line2)))
- strncat(type, cp, sizeof(type));
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ tpsize += scnprintf(type + tpsize,
+ sizeof(type) - tpsize, "%s", cp);
+ }
}

if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) {
line2 = line + strlen(SYSINFO_MODEL);

while ((cp = strtok_r(line2, "\n ", &line2))) {
- if (model[0])
- strcat(model, ",");
- if (strlen(model) + strlen(cp) < sizeof(model))
- strncat(model, cp, strlen(cp));
+ mdsize += scnprintf(model + mdsize, sizeof(type) - mdsize,
+ "%s%s", model[0] ? "," : "", cp);
}
break;
}
@@ -108,14 +111,15 @@ int get_cpuid(char *buffer, size_t sz)
strlen(SRVLVL_VERSION))) {
char *sep = strchr(cp, '=');

- strncat(version, sep + 1, sizeof(version));
+ vssize += scnprintf(version + vssize,
+ sizeof(version) - vssize, "%s", sep + 1);
}
if (!strncmp(cp, SRVLVL_AUTHORIZATION,
strlen(SRVLVL_AUTHORIZATION))) {
char *sep = strchr(cp, '=');

- strncat(authorization, sep + 1,
- sizeof(authorization));
+ atsize += scnprintf(authorization + atsize,
+ sizeof(authorization) - atsize, "%s", sep + 1);
}
}
}

Subject: [tip:perf/core] perf annotate: Scan cpuid for s390 and save machine type

Commit-ID: c59124fa59757fadc80ad881056a21f98c71b146
Gitweb: https://git.kernel.org/tip/c59124fa59757fadc80ad881056a21f98c71b146
Author: Thomas Richter <[email protected]>
AuthorDate: Tue, 13 Feb 2018 16:14:17 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 16 Feb 2018 15:16:57 -0300

perf annotate: Scan cpuid for s390 and save machine type

Scan the cpuid string and extract the type number for later use.

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/arch/s390/annotate/instructions.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c
index 8c72b44..01df9d8 100644
--- a/tools/perf/arch/s390/annotate/instructions.c
+++ b/tools/perf/arch/s390/annotate/instructions.c
@@ -23,12 +23,37 @@ static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *na
return ops;
}

+static int s390__cpuid_parse(struct arch *arch, char *cpuid)
+{
+ unsigned int family;
+ char model[16], model_c[16], cpumf_v[16], cpumf_a[16];
+ int ret;
+
+ /*
+ * cpuid string format:
+ * "IBM,family,model-capacity,model[,cpum_cf-version,cpum_cf-authorization]"
+ */
+ ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%s", &family, model_c,
+ model, cpumf_v, cpumf_a);
+ if (ret >= 2) {
+ arch->family = family;
+ arch->model = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
static int s390__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
+ int err = 0;
+
if (!arch->initialized) {
arch->initialized = true;
arch->associate_instruction_ops = s390__associate_ins_ops;
+ if (cpuid)
+ err = s390__cpuid_parse(arch, cpuid);
}

- return 0;
+ return err;
}

Subject: [tip:perf/core] perf record: Provide detailed information on s390 CPU

Commit-ID: eca0fa28cd0df7369701dbee0e30ddce19c039b8
Gitweb: https://git.kernel.org/tip/eca0fa28cd0df7369701dbee0e30ddce19c039b8
Author: Thomas Richter <[email protected]>
AuthorDate: Tue, 13 Feb 2018 16:14:16 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 16 Feb 2018 15:15:23 -0300

perf record: Provide detailed information on s390 CPU

When perf record ... is setup to record data, the s390 cpu information
was a fixed string "IBM/S390".

Replace this string with one containing more information about the
machine. The information included in the cpuid is a comma separated
list:

manufacturer,type,model-capacity,model[,version,authorization]
with

- manufacturer: up to 16 byte name of the manufacturer (IBM).
- type: a four digit number refering to the machine
generation.
- model-capacitiy: up to 16 characters describing number
of cpus etc.
- model: up to 16 characters describing model.
- version: the CPU-MF counter facility version number,
available on LPARs only, omitted on z/VM guests.
- authorization: the CPU-MF counter facility authorization level,
available on LPARs only, omitted on z/VM guests.

Before:

[root@s8360047 perf]# ./perf record -- sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.001 MB perf.data (4 samples) ]
[root@s8360047 perf]# ./perf report --header | fgrep cpuid
# cpuid : IBM/S390
[root@s8360047 perf]#

After:

[root@s35lp76 perf]# ./perf report --header|fgrep cpuid
# cpuid : IBM,3906,704,M03,3.5,002f
[root@s35lp76 perf]#

Signed-off-by: Thomas Richter <[email protected]>
Reviewed-by: Hendrik Brueckner <[email protected]>
Cc: Heiko Carstens <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Use scnprintf instead of strncat to fix build errors on gcc GNU C99 5.4.0 20160609 -march=zEC12 -m64 -mzarch -ggdb3 -O6 -std=gnu99 -fPIC -fno-omit-frame-pointer -funwind-tables -fstack-protector-all ]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/arch/s390/util/header.c | 130 +++++++++++++++++++++++++++++++++++--
1 file changed, 125 insertions(+), 5 deletions(-)

diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
index 9fa6c3e..a78064c 100644
--- a/tools/perf/arch/s390/util/header.c
+++ b/tools/perf/arch/s390/util/header.c
@@ -1,8 +1,9 @@
/*
* Implementation of get_cpuid().
*
- * Copyright 2014 IBM Corp.
+ * Copyright IBM Corp. 2014, 2018
* Author(s): Alexander Yarygin <[email protected]>
+ * 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)
@@ -13,16 +14,135 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>

#include "../../util/header.h"
+#include "../../util/util.h"
+
+#define SYSINFO_MANU "Manufacturer:"
+#define SYSINFO_TYPE "Type:"
+#define SYSINFO_MODEL "Model:"
+#define SRVLVL_CPUMF "CPU-MF:"
+#define SRVLVL_VERSION "version="
+#define SRVLVL_AUTHORIZATION "authorization="
+#define SYSINFO "/proc/sysinfo"
+#define SRVLVL "/proc/service_levels"

int get_cpuid(char *buffer, size_t sz)
{
- const char *cpuid = "IBM/S390";
+ char *cp, *line = NULL, *line2;
+ char type[8], model[33], version[8], manufacturer[32], authorization[8];
+ int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0;
+ int read;
+ unsigned long line_sz;
+ size_t nbytes;
+ FILE *sysinfo;
+
+ /*
+ * Scan /proc/sysinfo line by line and read out values for
+ * Manufacturer:, Type: and Model:, for example:
+ * Manufacturer: IBM
+ * Type: 2964
+ * Model: 702 N96
+ * The first word is the Model Capacity and the second word is
+ * Model (can be omitted). Both words have a maximum size of 16
+ * bytes.
+ */
+ memset(manufacturer, 0, sizeof(manufacturer));
+ memset(type, 0, sizeof(type));
+ memset(model, 0, sizeof(model));
+ memset(version, 0, sizeof(version));
+ memset(authorization, 0, sizeof(authorization));
+
+ sysinfo = fopen(SYSINFO, "r");
+ if (sysinfo == NULL)
+ return -1;
+
+ while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
+ if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) {
+ line2 = line + strlen(SYSINFO_MANU);
+
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ mfsize += scnprintf(manufacturer + mfsize,
+ sizeof(manufacturer) - mfsize, "%s", cp);
+ }
+ }
+
+ if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) {
+ line2 = line + strlen(SYSINFO_TYPE);
+
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ tpsize += scnprintf(type + tpsize,
+ sizeof(type) - tpsize, "%s", cp);
+ }
+ }
+
+ if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) {
+ line2 = line + strlen(SYSINFO_MODEL);
+
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ mdsize += scnprintf(model + mdsize, sizeof(type) - mdsize,
+ "%s%s", model[0] ? "," : "", cp);
+ }
+ break;
+ }
+ }
+ fclose(sysinfo);

- if (strlen(cpuid) + 1 > sz)
+ /* Missing manufacturer, type or model information should not happen */
+ if (!manufacturer[0] || !type[0] || !model[0])
return -1;

- strcpy(buffer, cpuid);
- return 0;
+ /*
+ * Scan /proc/service_levels and return the CPU-MF counter facility
+ * version number and authorization level.
+ * Optional, does not exist on z/VM guests.
+ */
+ sysinfo = fopen(SRVLVL, "r");
+ if (sysinfo == NULL)
+ goto skip_sysinfo;
+ while ((read = getline(&line, &line_sz, sysinfo)) != -1) {
+ if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF)))
+ continue;
+
+ line2 = line + strlen(SRVLVL_CPUMF);
+ while ((cp = strtok_r(line2, "\n ", &line2))) {
+ if (!strncmp(cp, SRVLVL_VERSION,
+ strlen(SRVLVL_VERSION))) {
+ char *sep = strchr(cp, '=');
+
+ vssize += scnprintf(version + vssize,
+ sizeof(version) - vssize, "%s", sep + 1);
+ }
+ if (!strncmp(cp, SRVLVL_AUTHORIZATION,
+ strlen(SRVLVL_AUTHORIZATION))) {
+ char *sep = strchr(cp, '=');
+
+ atsize += scnprintf(authorization + atsize,
+ sizeof(authorization) - atsize, "%s", sep + 1);
+ }
+ }
+ }
+ fclose(sysinfo);
+
+skip_sysinfo:
+ free(line);
+
+ if (version[0] && authorization[0] )
+ nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s",
+ manufacturer, type, model, version,
+ authorization);
+ else
+ nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type,
+ model);
+ return (nbytes >= sz) ? -1 : 0;
+}
+
+char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
+{
+ char *buf = malloc(128);
+
+ if (buf && get_cpuid(buf, 128) < 0)
+ zfree(&buf);
+ return buf;
}

Subject: [tip:perf/core] perf cpuid: Introduce a platform specific cpuid compare function

Commit-ID: 4cb7d3ecfca90684ad00f893c34a2028fcc5f764
Gitweb: https://git.kernel.org/tip/4cb7d3ecfca90684ad00f893c34a2028fcc5f764
Author: Thomas Richter <[email protected]>
AuthorDate: Tue, 13 Feb 2018 16:14:18 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 16 Feb 2018 15:16:57 -0300

perf cpuid: Introduce a platform specific cpuid compare function

The function get_cpuid_str() is called by perf_pmu__getcpuid() and on
s390 returns a complete description of the CPU and its capabilities,
which is a comma separated list.

To map the CPU type with the value defined in the
pmu-events/arch/s390/mapfile.csv, introduce an architecture specific
cpuid compare function named strcmp_cpuid_str()

The currently used regex algorithm is defined as the weak default and
will be used if no platform specific one is defined. This matches the
current behavior.

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/arch/s390/util/header.c | 18 +++++++++++++++
tools/perf/util/header.h | 1 +
tools/perf/util/pmu.c | 47 +++++++++++++++++++++++---------------
3 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c
index a78064c..231294b 100644
--- a/tools/perf/arch/s390/util/header.c
+++ b/tools/perf/arch/s390/util/header.c
@@ -146,3 +146,21 @@ char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
zfree(&buf);
return buf;
}
+
+/*
+ * Compare the cpuid string returned by get_cpuid() function
+ * with the name generated by the jevents file read from
+ * pmu-events/arch/s390/mapfile.csv.
+ *
+ * Parameter mapcpuid is the cpuid as stored in the
+ * pmu-events/arch/s390/mapfile.csv. This is just the type number.
+ * Parameter cpuid is the cpuid returned by function get_cpuid().
+ */
+int strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
+{
+ char *cp = strchr(cpuid, ',');
+
+ if (cp == NULL)
+ return -1;
+ return strncmp(cp + 1, mapcpuid, strlen(mapcpuid));
+}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index f28aaaa..942bdec 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -174,4 +174,5 @@ int write_padded(struct feat_fd *fd, const void *bf,
int get_cpuid(char *buffer, size_t sz);

char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused);
+int strcmp_cpuid_str(const char *s1, const char *s2);
#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 57e38fd..1111d5b 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -576,6 +576,34 @@ char * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
return NULL;
}

+/* Return zero when the cpuid from the mapfile.csv matches the
+ * cpuid string generated on this platform.
+ * Otherwise return non-zero.
+ */
+int __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
+{
+ regex_t re;
+ regmatch_t pmatch[1];
+ int match;
+
+ if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) {
+ /* Warn unable to generate match particular string. */
+ pr_info("Invalid regular expression %s\n", mapcpuid);
+ return 1;
+ }
+
+ match = !regexec(&re, cpuid, 1, pmatch, 0);
+ regfree(&re);
+ if (match) {
+ size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
+
+ /* Verify the entire string matched. */
+ if (match_len == strlen(cpuid))
+ return 0;
+ }
+ return 1;
+}
+
static char *perf_pmu__getcpuid(struct perf_pmu *pmu)
{
char *cpuid;
@@ -610,31 +638,14 @@ struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu)

i = 0;
for (;;) {
- regex_t re;
- regmatch_t pmatch[1];
- int match;
-
map = &pmu_events_map[i++];
if (!map->table) {
map = NULL;
break;
}

- if (regcomp(&re, map->cpuid, REG_EXTENDED) != 0) {
- /* Warn unable to generate match particular string. */
- pr_info("Invalid regular expression %s\n", map->cpuid);
+ if (!strcmp_cpuid_str(map->cpuid, cpuid))
break;
- }
-
- match = !regexec(&re, cpuid, 1, pmatch, 0);
- regfree(&re);
- if (match) {
- size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
-
- /* Verify the entire string matched. */
- if (match_len == strlen(cpuid))
- break;
- }
}
free(cpuid);
return map;

Subject: [tip:perf/core] perf test: Fix test case 23 for s390 z/VM or KVM guests

Commit-ID: b3be39c51cc58eb60c698cf64987e9d465a9263a
Gitweb: https://git.kernel.org/tip/b3be39c51cc58eb60c698cf64987e9d465a9263a
Author: Thomas Richter <[email protected]>
AuthorDate: Tue, 13 Feb 2018 16:14:19 +0100
Committer: Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 16 Feb 2018 15:16:57 -0300

perf test: Fix test case 23 for s390 z/VM or KVM guests

On s390 perf can be executed on a LPAR with support for hardware events
(i. e. cycles) or on a z/VM or KVM guest where no hardware events are
supported. In this environment use software event named cpu-clock for
this test case.

Use the cpuid infrastructure functions to determine the cpuid on s390
which contains an indication of the cpu counter facility availability.

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/tests/code-reading.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 3bf7b14..c7115d3 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -482,6 +482,34 @@ static void fs_something(void)
}
}

+static const char *do_determine_event(bool excl_kernel)
+{
+ const char *event = excl_kernel ? "cycles:u" : "cycles";
+
+#ifdef __s390x__
+ char cpuid[128], model[16], model_c[16], cpum_cf_v[16];
+ unsigned int family;
+ int ret, cpum_cf_a;
+
+ if (get_cpuid(cpuid, sizeof(cpuid)))
+ goto out_clocks;
+ ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%x", &family, model_c,
+ model, cpum_cf_v, &cpum_cf_a);
+ if (ret != 5) /* Not available */
+ goto out_clocks;
+ if (excl_kernel && (cpum_cf_a & 4))
+ return event;
+ if (!excl_kernel && (cpum_cf_a & 2))
+ return event;
+
+ /* Fall through: missing authorization */
+out_clocks:
+ event = excl_kernel ? "cpu-clock:u" : "cpu-clock";
+
+#endif
+ return event;
+}
+
static void do_something(void)
{
fs_something();
@@ -592,10 +620,7 @@ static int do_test_code_reading(bool try_kcore)

perf_evlist__set_maps(evlist, cpus, threads);

- if (excl_kernel)
- str = "cycles:u";
- else
- str = "cycles";
+ str = do_determine_event(excl_kernel);
pr_debug("Parsing event '%s'\n", str);
ret = parse_events(evlist, str, NULL);
if (ret < 0) {