From d2785de15f1bd42d613d56bbac5a007e7293b874 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 12 Feb 2018 13:32:37 -0700 Subject: perf auxtrace arm: Fixing uninitialised variable When working natively on arm64 the compiler gets pesky and complains that variable 'i' is uninitialised, something that breaks the compilation. Here no further checks are needed since variable 'found_spe' can only be true if variable 'i' has been initialised as part of the for loop. Signed-off-by: Mathieu Poirier Cc: Alexander Shishkin Cc: Jin Yao Cc: Namhyung Kim Cc: Peter Zijlstra Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1518467557-18505-4-git-send-email-mathieu.poirier@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/util/auxtrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util/auxtrace.c index 2323581b157d..fa639e3e52ac 100644 --- a/tools/perf/arch/arm/util/auxtrace.c +++ b/tools/perf/arch/arm/util/auxtrace.c @@ -68,7 +68,7 @@ struct auxtrace_record bool found_spe = false; static struct perf_pmu **arm_spe_pmus = NULL; static int nr_spes = 0; - int i; + int i = 0; if (!evlist) return NULL; -- cgit v1.2.1 From 796bfadd831bdef0de06cd0253398c3fe011e459 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Mon, 12 Feb 2018 16:38:57 -0700 Subject: perf cs-etm: Properly deal with cpu maps This patch allows the CoreSight AUX info section to fit topologies where only a subset of all available CPUs are present, avoiding at the same time accessing the ETM configuration areas of CPUs that have been offlined. Signed-off-by: Mathieu Poirier Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1518478737-24649-1-git-send-email-mathieu.poirier@linaro.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/arm/util/cs-etm.c | 51 +++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/arm/util/cs-etm.c b/tools/perf/arch/arm/util/cs-etm.c index fbfc055d3f4d..5c655ad4621e 100644 --- a/tools/perf/arch/arm/util/cs-etm.c +++ b/tools/perf/arch/arm/util/cs-etm.c @@ -298,12 +298,17 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, { int i; int etmv3 = 0, etmv4 = 0; - const struct cpu_map *cpus = evlist->cpus; + struct cpu_map *event_cpus = evlist->cpus; + struct cpu_map *online_cpus = cpu_map__new(NULL); /* cpu map is not empty, we have specific CPUs to work with */ - if (!cpu_map__empty(cpus)) { - for (i = 0; i < cpu_map__nr(cpus); i++) { - if (cs_etm_is_etmv4(itr, cpus->map[i])) + if (!cpu_map__empty(event_cpus)) { + for (i = 0; i < cpu__max_cpu(); i++) { + if (!cpu_map__has(event_cpus, i) || + !cpu_map__has(online_cpus, i)) + continue; + + if (cs_etm_is_etmv4(itr, i)) etmv4++; else etmv3++; @@ -311,6 +316,9 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, } else { /* get configuration for all CPUs in the system */ for (i = 0; i < cpu__max_cpu(); i++) { + if (!cpu_map__has(online_cpus, i)) + continue; + if (cs_etm_is_etmv4(itr, i)) etmv4++; else @@ -318,6 +326,8 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, } } + cpu_map__put(online_cpus); + return (CS_ETM_HEADER_SIZE + (etmv4 * CS_ETMV4_PRIV_SIZE) + (etmv3 * CS_ETMV3_PRIV_SIZE)); @@ -447,7 +457,9 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, int i; u32 offset; u64 nr_cpu, type; - const struct cpu_map *cpus = session->evlist->cpus; + struct cpu_map *cpu_map; + struct cpu_map *event_cpus = session->evlist->cpus; + struct cpu_map *online_cpus = cpu_map__new(NULL); struct cs_etm_recording *ptr = container_of(itr, struct cs_etm_recording, itr); struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu; @@ -458,8 +470,21 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, if (!session->evlist->nr_mmaps) return -EINVAL; - /* If the cpu_map is empty all CPUs are involved */ - nr_cpu = cpu_map__empty(cpus) ? cpu__max_cpu() : cpu_map__nr(cpus); + /* If the cpu_map is empty all online CPUs are involved */ + if (cpu_map__empty(event_cpus)) { + cpu_map = online_cpus; + } else { + /* Make sure all specified CPUs are online */ + for (i = 0; i < cpu_map__nr(event_cpus); i++) { + if (cpu_map__has(event_cpus, i) && + !cpu_map__has(online_cpus, i)) + return -EINVAL; + } + + cpu_map = event_cpus; + } + + nr_cpu = cpu_map__nr(cpu_map); /* Get PMU type as dynamically assigned by the core */ type = cs_etm_pmu->type; @@ -472,15 +497,11 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, offset = CS_ETM_SNAPSHOT + 1; - /* cpu map is not empty, we have specific CPUs to work with */ - if (!cpu_map__empty(cpus)) { - for (i = 0; i < cpu_map__nr(cpus) && offset < priv_size; i++) - cs_etm_get_metadata(cpus->map[i], &offset, itr, info); - } else { - /* get configuration for all CPUs in the system */ - for (i = 0; i < cpu__max_cpu(); i++) + for (i = 0; i < cpu__max_cpu() && offset < priv_size; i++) + if (cpu_map__has(cpu_map, i)) cs_etm_get_metadata(i, &offset, itr, info); - } + + cpu_map__put(online_cpus); return 0; } -- cgit v1.2.1 From 8e2ff72aa35e1a8a53894ae46751a83543338e14 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Mon, 29 Jan 2018 14:04:16 +0530 Subject: perf powerpc: Generate system call table from asm/unistd.h This should speed up accessing new system calls introduced with the kernel rather than waiting for libaudit updates to include them. Signed-off-by: Ravi Bangoria Cc: Alexander Shishkin Cc: Hendrik Brueckner Cc: Jiri Olsa Cc: Michael Ellerman Cc: Namhyung Kim Cc: Thomas Richter Cc: linuxppc-dev@lists.ozlabs.org Link: http://lkml.kernel.org/r/20180129083417.31240-3-ravi.bangoria@linux.vnet.ibm.com [ Made it generate syscall_32.c as well to fix the build on 32-bit ppc ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/Makefile | 25 +++++++++++++++ .../perf/arch/powerpc/entry/syscalls/mksyscalltbl | 37 ++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100755 tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile index 42dab7c8f508..a111239df182 100644 --- a/tools/perf/arch/powerpc/Makefile +++ b/tools/perf/arch/powerpc/Makefile @@ -6,3 +6,28 @@ endif HAVE_KVM_STAT_SUPPORT := 1 PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 PERF_HAVE_JITDUMP := 1 + +# +# Syscall table generation for perf +# + +out := $(OUTPUT)arch/powerpc/include/generated/asm +header32 := $(out)/syscalls_32.c +header64 := $(out)/syscalls_64.c +sysdef := $(srctree)/tools/arch/powerpc/include/uapi/asm/unistd.h +sysprf := $(srctree)/tools/perf/arch/powerpc/entry/syscalls/ +systbl := $(sysprf)/mksyscalltbl + +# Create output directory if not already present +_dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') + +$(header64): $(sysdef) $(systbl) + $(Q)$(SHELL) '$(systbl)' '64' '$(CC)' $(sysdef) > $@ + +$(header32): $(sysdef) $(systbl) + $(Q)$(SHELL) '$(systbl)' '32' '$(CC)' $(sysdef) > $@ + +clean:: + $(call QUIET_CLEAN, powerpc) $(RM) $(header32) $(header64) + +archheaders: $(header32) $(header64) diff --git a/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl b/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl new file mode 100755 index 000000000000..ef52e1dd694b --- /dev/null +++ b/tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl @@ -0,0 +1,37 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Generate system call table for perf. Derived from +# s390 script. +# +# Copyright IBM Corp. 2017 +# Author(s): Hendrik Brueckner +# Changed by: Ravi Bangoria + +wordsize=$1 +gcc=$2 +input=$3 + +if ! test -r $input; then + echo "Could not read input file" >&2 + exit 1 +fi + +create_table() +{ + local wordsize=$1 + local max_nr + + echo "static const char *syscalltbl_powerpc_${wordsize}[] = {" + while read sc nr; do + printf '\t[%d] = "%s",\n' $nr $sc + max_nr=$nr + done + echo '};' + echo "#define SYSCALLTBL_POWERPC_${wordsize}_MAX_ID $max_nr" +} + +$gcc -m${wordsize} -E -dM -x c $input \ + |sed -ne 's/^#define __NR_//p' \ + |sort -t' ' -k2 -nu \ + |create_table ${wordsize} -- cgit v1.2.1 From eca0fa28cd0df7369701dbee0e30ddce19c039b8 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 13 Feb 2018 16:14:16 +0100 Subject: 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 Reviewed-by: Hendrik Brueckner Cc: Heiko Carstens Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180213151419.80737-1-tmricht@linux.vnet.ibm.com [ 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 --- tools/perf/arch/s390/util/header.c | 130 +++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 5 deletions(-) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c index 9fa6c3e5782c..a78064c25ced 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 + * Thomas Richter * * 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 #include #include +#include #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; } -- cgit v1.2.1 From c59124fa59757fadc80ad881056a21f98c71b146 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 13 Feb 2018 16:14:17 +0100 Subject: 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 Reviewed-by: Hendrik Brueckner Cc: Heiko Carstens Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180213151419.80737-2-tmricht@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/s390/annotate/instructions.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'tools/perf/arch') 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; } -- cgit v1.2.1 From 4cb7d3ecfca90684ad00f893c34a2028fcc5f764 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 13 Feb 2018 16:14:18 +0100 Subject: 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 Reviewed-by: Hendrik Brueckner Cc: Heiko Carstens Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180213151419.80737-3-tmricht@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/s390/util/header.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'tools/perf/arch') diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c index a78064c25ced..231294b80dc4 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)); +} -- cgit v1.2.1