diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 11:06:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 11:06:34 -0700 |
commit | 486adcea4a63bec206cba6f0d7f301fb945ae9d3 (patch) | |
tree | 1cdf7fed3628390186b5493087612f3681e9e912 /tools/perf/arch | |
parent | 701f3b314905ac05f09fc052c87b022825d831f2 (diff) | |
parent | 1159e09476536250c2a0173d4298d15114df7a89 (diff) |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"The main kernel side changes were:
- Modernize the kprobe and uprobe creation/destruction tooling ABIs:
The existing text based APIs (kprobe_events and uprobe_events in
tracefs), are naive, limited ABIs in that they require user-space
to clean up after themselves, which is both difficult and fragile
if the tool is buggy or exits unexpectedly. In other words they are
not really suited for modern, robust tooling.
So introduce a modern, file descriptor based ABI that does not have
these limitations: introduce the 'perf_kprobe' and 'perf_uprobe'
PMUs and extend the perf_event_open() syscall to create events with
a kprobe/uprobe attached to them. These [k,u]probe are associated
with this file descriptor, so they are not available in tracefs.
(Song Liu)
- Intel Cannon Lake CPU support (Harry Pan)
- Intel PT cleanups (Alexander Shishkin)
- Improve the performance of pinned/flexible event groups by using RB
trees (Alexey Budankov)
- Add PERF_EVENT_IOC_MODIFY_ATTRIBUTES which allows the modification
of hardware breakpoints, which new ABI variant massively speeds up
existing tooling that uses hardware breakpoints to instrument (and
debug) memory usage.
(Milind Chabbi, Jiri Olsa)
- Various Intel PEBS handling fixes and improvements, and other Intel
PMU improvements (Kan Liang)
- Various perf core improvements and optimizations (Peter Zijlstra)
- ... misc cleanups, fixes and updates.
There's over 200 tooling commits, here's an (imperfect) list of
highlights:
- 'perf annotate' improvements:
* Recognize and handle jumps to other functions as calls, which
improves the navigation along jumps and back. (Arnaldo Carvalho
de Melo)
* Add the 'P' hotkey in TUI annotation to dump annotation output
into a file, to ease e-mail reporting of annotation details.
(Arnaldo Carvalho de Melo)
* Add an IPC/cycles column to the TUI (Jin Yao)
* Improve s390 assembly annotation (Thomas Richter)
* Refactor the output formatting logic to better separate it into
interactive and non-interactive features and add the --stdio2
output variant to demonstrate this. (Arnaldo Carvalho de Melo)
- 'perf script' improvements:
* Add Python 3 support (Jaroslav Škarvada)
* Add --show-round-event (Jiri Olsa)
- 'perf c2c' improvements:
* Add NUMA analysis support (Jiri Olsa)
- 'perf trace' improvements:
* Improve PowerPC support (Ravi Bangoria)
- 'perf inject' improvements:
* Integrate ARM CoreSight traces (Robert Walker)
- 'perf stat' improvements:
* Add the --interval-count option (yuzhoujian)
* Add the --timeout option (yuzhoujian)
- 'perf sched' improvements (Changbin Du)
- Vendor events improvements :
* Add IBM s390 vendor events (Thomas Richter)
* Add and improve arm64 vendor events (John Garry, Ganapatrao
Kulkarni)
* Update POWER9 vendor events (Sukadev Bhattiprolu)
- Intel PT tooling improvements (Adrian Hunter)
- PMU handling improvements (Agustin Vega-Frias)
- Record machine topology in perf.data (Jiri Olsa)
- Various overwrite related cleanups (Kan Liang)
- Add arm64 dwarf post unwind support (Kim Phillips, Jean Pihet)
- ... and lots of other changes, cleanups and fixes, see the shortlog
and Git history for details"
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (262 commits)
perf/x86/intel: Enable C-state residency events for Cannon Lake
perf/x86/intel: Add Cannon Lake support for RAPL profiling
perf/x86/pt, coresight: Clean up address filter structure
perf vendor events s390: Add JSON files for IBM z14
perf vendor events s390: Add JSON files for IBM z13
perf vendor events s390: Add JSON files for IBM zEC12 zBC12
perf vendor events s390: Add JSON files for IBM z196
perf vendor events s390: Add JSON files for IBM z10EC z10BC
perf mmap: Be consistent when checking for an unmaped ring buffer
perf mmap: Fix accessing unmapped mmap in perf_mmap__read_done()
perf build: Fix check-headers.sh opts assignment
perf/x86: Update rdpmc_always_available static key to the modern API
perf annotate: Use absolute addresses to calculate jump target offsets
perf annotate: Defer searching for comma in raw line till it is needed
perf annotate: Support jumping from one function to another
perf annotate: Add "_local" to jump/offset validation routines
perf python: Reference Py_None before returning it
perf annotate: Mark jumps to outher functions with the call arrow
perf annotate: Pass function descriptor to its instruction parsing routines
perf annotate: No need to calculate notes->start twice
...
Diffstat (limited to 'tools/perf/arch')
-rw-r--r-- | tools/perf/arch/arm/util/auxtrace.c | 2 | ||||
-rw-r--r-- | tools/perf/arch/arm/util/cs-etm.c | 51 | ||||
-rw-r--r-- | tools/perf/arch/arm64/include/arch-tests.h | 12 | ||||
-rw-r--r-- | tools/perf/arch/arm64/tests/Build | 2 | ||||
-rw-r--r-- | tools/perf/arch/arm64/tests/arch-tests.c | 16 | ||||
-rw-r--r-- | tools/perf/arch/arm64/util/Build | 1 | ||||
-rw-r--r-- | tools/perf/arch/arm64/util/unwind-libdw.c | 60 | ||||
-rw-r--r-- | tools/perf/arch/powerpc/Makefile | 25 | ||||
-rwxr-xr-x | tools/perf/arch/powerpc/entry/syscalls/mksyscalltbl | 37 | ||||
-rw-r--r-- | tools/perf/arch/s390/annotate/instructions.c | 144 | ||||
-rw-r--r-- | tools/perf/arch/s390/util/header.c | 148 | ||||
-rw-r--r-- | tools/perf/arch/x86/tests/perf-time-to-tsc.c | 10 | ||||
-rw-r--r-- | tools/perf/arch/x86/util/auxtrace.c | 14 |
13 files changed, 488 insertions, 34 deletions
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; 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; } diff --git a/tools/perf/arch/arm64/include/arch-tests.h b/tools/perf/arch/arm64/include/arch-tests.h new file mode 100644 index 000000000000..90ec4c8cb880 --- /dev/null +++ b/tools/perf/arch/arm64/include/arch-tests.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef ARCH_TESTS_H +#define ARCH_TESTS_H + +#ifdef HAVE_DWARF_UNWIND_SUPPORT +struct thread; +struct perf_sample; +#endif + +extern struct test arch_tests[]; + +#endif diff --git a/tools/perf/arch/arm64/tests/Build b/tools/perf/arch/arm64/tests/Build index b30eff9bcc83..883c57ff0c08 100644 --- a/tools/perf/arch/arm64/tests/Build +++ b/tools/perf/arch/arm64/tests/Build @@ -1,2 +1,4 @@ libperf-y += regs_load.o libperf-y += dwarf-unwind.o + +libperf-y += arch-tests.o diff --git a/tools/perf/arch/arm64/tests/arch-tests.c b/tools/perf/arch/arm64/tests/arch-tests.c new file mode 100644 index 000000000000..5b1543c98022 --- /dev/null +++ b/tools/perf/arch/arm64/tests/arch-tests.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <string.h> +#include "tests/tests.h" +#include "arch-tests.h" + +struct test arch_tests[] = { +#ifdef HAVE_DWARF_UNWIND_SUPPORT + { + .desc = "DWARF unwind", + .func = test__dwarf_unwind, + }, +#endif + { + .func = NULL, + }, +}; diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build index c0b8dfef98ba..68f8a8eb3ad0 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -2,6 +2,7 @@ libperf-y += header.o libperf-y += sym-handling.o libperf-$(CONFIG_DWARF) += dwarf-regs.o libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \ ../../arm/util/auxtrace.o \ diff --git a/tools/perf/arch/arm64/util/unwind-libdw.c b/tools/perf/arch/arm64/util/unwind-libdw.c new file mode 100644 index 000000000000..7623d85e77f3 --- /dev/null +++ b/tools/perf/arch/arm64/util/unwind-libdw.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <elfutils/libdwfl.h> +#include "../../util/unwind-libdw.h" +#include "../../util/perf_regs.h" +#include "../../util/event.h" + +bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg) +{ + struct unwind_info *ui = arg; + struct regs_dump *user_regs = &ui->sample->user_regs; + Dwarf_Word dwarf_regs[PERF_REG_ARM64_MAX], dwarf_pc; + +#define REG(r) ({ \ + Dwarf_Word val = 0; \ + perf_reg_value(&val, user_regs, PERF_REG_ARM64_##r); \ + val; \ +}) + + dwarf_regs[0] = REG(X0); + dwarf_regs[1] = REG(X1); + dwarf_regs[2] = REG(X2); + dwarf_regs[3] = REG(X3); + dwarf_regs[4] = REG(X4); + dwarf_regs[5] = REG(X5); + dwarf_regs[6] = REG(X6); + dwarf_regs[7] = REG(X7); + dwarf_regs[8] = REG(X8); + dwarf_regs[9] = REG(X9); + dwarf_regs[10] = REG(X10); + dwarf_regs[11] = REG(X11); + dwarf_regs[12] = REG(X12); + dwarf_regs[13] = REG(X13); + dwarf_regs[14] = REG(X14); + dwarf_regs[15] = REG(X15); + dwarf_regs[16] = REG(X16); + dwarf_regs[17] = REG(X17); + dwarf_regs[18] = REG(X18); + dwarf_regs[19] = REG(X19); + dwarf_regs[20] = REG(X20); + dwarf_regs[21] = REG(X21); + dwarf_regs[22] = REG(X22); + dwarf_regs[23] = REG(X23); + dwarf_regs[24] = REG(X24); + dwarf_regs[25] = REG(X25); + dwarf_regs[26] = REG(X26); + dwarf_regs[27] = REG(X27); + dwarf_regs[28] = REG(X28); + dwarf_regs[29] = REG(X29); + dwarf_regs[30] = REG(LR); + dwarf_regs[31] = REG(SP); + + if (!dwfl_thread_state_registers(thread, 0, PERF_REG_ARM64_MAX, + dwarf_regs)) + return false; + + dwarf_pc = REG(PC); + dwfl_thread_state_register_pc(thread, dwarf_pc); + + return true; +} 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 <brueckner@linux.vnet.ibm.com> +# Changed by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> + +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} diff --git a/tools/perf/arch/s390/annotate/instructions.c b/tools/perf/arch/s390/annotate/instructions.c index 8c72b44444cb..cee4e2f7c057 100644 --- a/tools/perf/arch/s390/annotate/instructions.c +++ b/tools/perf/arch/s390/annotate/instructions.c @@ -1,6 +1,113 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> +static int s390_call__parse(struct arch *arch, struct ins_operands *ops, + struct map_symbol *ms) +{ + char *endptr, *tok, *name; + struct map *map = ms->map; + struct addr_map_symbol target = { + .map = map, + }; + + tok = strchr(ops->raw, ','); + if (!tok) + return -1; + + ops->target.addr = strtoull(tok + 1, &endptr, 16); + + name = strchr(endptr, '<'); + if (name == NULL) + return -1; + + name++; + + if (arch->objdump.skip_functions_char && + strchr(name, arch->objdump.skip_functions_char)) + return -1; + + tok = strchr(name, '>'); + if (tok == NULL) + return -1; + + *tok = '\0'; + ops->target.name = strdup(name); + *tok = '>'; + + if (ops->target.name == NULL) + return -1; + target.addr = map__objdump_2mem(map, ops->target.addr); + + if (map_groups__find_ams(&target) == 0 && + map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr) + ops->target.sym = target.sym; + + return 0; +} + +static int call__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops); + +static struct ins_ops s390_call_ops = { + .parse = s390_call__parse, + .scnprintf = call__scnprintf, +}; + +static int s390_mov__parse(struct arch *arch __maybe_unused, + struct ins_operands *ops, + struct map_symbol *ms __maybe_unused) +{ + char *s = strchr(ops->raw, ','), *target, *endptr; + + if (s == NULL) + return -1; + + *s = '\0'; + ops->source.raw = strdup(ops->raw); + *s = ','; + + if (ops->source.raw == NULL) + return -1; + + target = ++s; + ops->target.raw = strdup(target); + if (ops->target.raw == NULL) + goto out_free_source; + + ops->target.addr = strtoull(target, &endptr, 16); + if (endptr == target) + goto out_free_target; + + s = strchr(endptr, '<'); + if (s == NULL) + goto out_free_target; + endptr = strchr(s + 1, '>'); + if (endptr == NULL) + goto out_free_target; + + *endptr = '\0'; + ops->target.name = strdup(s + 1); + *endptr = '>'; + if (ops->target.name == NULL) + goto out_free_target; + + return 0; + +out_free_target: + zfree(&ops->target.raw); +out_free_source: + zfree(&ops->source.raw); + return -1; +} + +static int mov__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops); + +static struct ins_ops s390_mov_ops = { + .parse = s390_mov__parse, + .scnprintf = mov__scnprintf, +}; + static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *name) { struct ins_ops *ops = NULL; @@ -14,21 +121,54 @@ static struct ins_ops *s390__associate_ins_ops(struct arch *arch, const char *na if (!strcmp(name, "bras") || !strcmp(name, "brasl") || !strcmp(name, "basr")) - ops = &call_ops; + ops = &s390_call_ops; if (!strcmp(name, "br")) ops = &ret_ops; + /* override load/store relative to PC */ + if (!strcmp(name, "lrl") || + !strcmp(name, "lgrl") || + !strcmp(name, "lgfrl") || + !strcmp(name, "llgfrl") || + !strcmp(name, "strl") || + !strcmp(name, "stgrl")) + ops = &s390_mov_ops; if (ops) arch__associate_ins_ops(arch, name, ops); 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; } diff --git a/tools/perf/arch/s390/util/header.c b/tools/perf/arch/s390/util/header.c index 9fa6c3e5782c..a4c30f1c70be 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 <yarygin@linux.vnet.ibm.com> + * Thomas Richter <tmricht@linux.vnet.ibm.com> * * 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,153 @@ #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); - if (strlen(cpuid) + 1 > sz) + 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(model) - mdsize, + "%s%s", model[0] ? "," : "", cp); + } + break; + } + } + fclose(sysinfo); + + /* 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; +} + +/* + * 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/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index 06abe8108b33..7a7721604b86 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c @@ -60,6 +60,7 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe union perf_event *event; u64 test_tsc, comm1_tsc, comm2_tsc; u64 test_time, comm1_time = 0, comm2_time = 0; + struct perf_mmap *md; threads = thread_map__new(-1, getpid(), UINT_MAX); CHECK_NOT_NULL__(threads); @@ -109,7 +110,11 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe perf_evlist__disable(evlist); for (i = 0; i < evlist->nr_mmaps; i++) { - while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { + md = &evlist->mmap[i]; + if (perf_mmap__read_init(md) < 0) + continue; + + while ((event = perf_mmap__read_event(md)) != NULL) { struct perf_sample sample; if (event->header.type != PERF_RECORD_COMM || @@ -128,8 +133,9 @@ int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe comm2_time = sample.time; } next_event: - perf_evlist__mmap_consume(evlist, i); + perf_mmap__consume(md); } + perf_mmap__read_done(md); } if (!comm1_time || !comm2_time) diff --git a/tools/perf/arch/x86/util/auxtrace.c b/tools/perf/arch/x86/util/auxtrace.c index 6aa3f2a38321..b135af62011c 100644 --- a/tools/perf/arch/x86/util/auxtrace.c +++ b/tools/perf/arch/x86/util/auxtrace.c @@ -37,15 +37,11 @@ struct auxtrace_record *auxtrace_record__init_intel(struct perf_evlist *evlist, intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME); intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME); - if (evlist) { - evlist__for_each_entry(evlist, evsel) { - if (intel_pt_pmu && - evsel->attr.type == intel_pt_pmu->type) - found_pt = true; - if (intel_bts_pmu && - evsel->attr.type == intel_bts_pmu->type) - found_bts = true; - } + evlist__for_each_entry(evlist, evsel) { + if (intel_pt_pmu && evsel->attr.type == intel_pt_pmu->type) + found_pt = true; + if (intel_bts_pmu && evsel->attr.type == intel_bts_pmu->type) + found_bts = true; } if (found_pt && found_bts) { |