perf tools powerpc: Add support for extended register capability

Add extended regs to sample_reg_mask in the tool side to use with `-I?`
option. Perf tools side uses extended mask to display the platform
supported register names (with -I? option) to the user and also send
this mask to the kernel to capture the extended registers in each
sample. Hence decide the mask value based on the processor version.

Currently definitions for `mfspr`, `SPRN_PVR` are part of
`arch/powerpc/util/header.c`. Move this to a header file so that these
definitions can be re-used in other source files as well.

Signed-off-by: Anju T Sudhakar <anju@linux.vnet.ibm.com>
Reviewed-by: Kajol Jain <kjain@linux.ibm.com>
Reviewed-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
Reviewed--by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Tested-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michael Neuling <mikey@neuling.org> <mikey@neuling.org>
Cc: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Cc: linuxppc-dev@lists.ozlabs.org
[Decide extended mask at run time based on platform]
Signed-off-by: Athira Jajeev <atrajeev@linux.vnet.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Anju T Sudhakar 2020-08-07 06:11:18 -04:00 committed by Arnaldo Carvalho de Melo
parent d01541d006
commit 33583e6950
5 changed files with 82 additions and 10 deletions

View File

@ -48,6 +48,18 @@ enum perf_event_powerpc_regs {
PERF_REG_POWERPC_DSISR, PERF_REG_POWERPC_DSISR,
PERF_REG_POWERPC_SIER, PERF_REG_POWERPC_SIER,
PERF_REG_POWERPC_MMCRA, PERF_REG_POWERPC_MMCRA,
PERF_REG_POWERPC_MAX, /* Extended registers */
PERF_REG_POWERPC_MMCR0,
PERF_REG_POWERPC_MMCR1,
PERF_REG_POWERPC_MMCR2,
/* Max regs without the extended regs */
PERF_REG_POWERPC_MAX = PERF_REG_POWERPC_MMCRA + 1,
}; };
#define PERF_REG_PMU_MASK ((1ULL << PERF_REG_POWERPC_MAX) - 1)
/* PERF_REG_EXTENDED_MASK value for CPU_FTR_ARCH_300 */
#define PERF_REG_PMU_MASK_300 (((1ULL << (PERF_REG_POWERPC_MMCR2 + 1)) - 1) - PERF_REG_PMU_MASK)
#define PERF_REG_MAX_ISA_300 (PERF_REG_POWERPC_MMCR2 + 1)
#endif /* _UAPI_ASM_POWERPC_PERF_REGS_H */ #endif /* _UAPI_ASM_POWERPC_PERF_REGS_H */

View File

@ -64,7 +64,10 @@ static const char *reg_names[] = {
[PERF_REG_POWERPC_DAR] = "dar", [PERF_REG_POWERPC_DAR] = "dar",
[PERF_REG_POWERPC_DSISR] = "dsisr", [PERF_REG_POWERPC_DSISR] = "dsisr",
[PERF_REG_POWERPC_SIER] = "sier", [PERF_REG_POWERPC_SIER] = "sier",
[PERF_REG_POWERPC_MMCRA] = "mmcra" [PERF_REG_POWERPC_MMCRA] = "mmcra",
[PERF_REG_POWERPC_MMCR0] = "mmcr0",
[PERF_REG_POWERPC_MMCR1] = "mmcr1",
[PERF_REG_POWERPC_MMCR2] = "mmcr2",
}; };
static inline const char *perf_reg_name(int id) static inline const char *perf_reg_name(int id)

View File

@ -7,17 +7,10 @@
#include <string.h> #include <string.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include "header.h" #include "header.h"
#include "utils_header.h"
#include "metricgroup.h" #include "metricgroup.h"
#include <api/fs/fs.h> #include <api/fs/fs.h>
#define mfspr(rn) ({unsigned long rval; \
asm volatile("mfspr %0," __stringify(rn) \
: "=r" (rval)); rval; })
#define SPRN_PVR 0x11F /* Processor Version Register */
#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
int int
get_cpuid(char *buffer, size_t sz) get_cpuid(char *buffer, size_t sz)
{ {

View File

@ -6,9 +6,15 @@
#include "../../../util/perf_regs.h" #include "../../../util/perf_regs.h"
#include "../../../util/debug.h" #include "../../../util/debug.h"
#include "../../../util/event.h"
#include "../../../util/header.h"
#include "../../../perf-sys.h"
#include "utils_header.h"
#include <linux/kernel.h> #include <linux/kernel.h>
#define PVR_POWER9 0x004E
const struct sample_reg sample_reg_masks[] = { const struct sample_reg sample_reg_masks[] = {
SMPL_REG(r0, PERF_REG_POWERPC_R0), SMPL_REG(r0, PERF_REG_POWERPC_R0),
SMPL_REG(r1, PERF_REG_POWERPC_R1), SMPL_REG(r1, PERF_REG_POWERPC_R1),
@ -55,6 +61,9 @@ const struct sample_reg sample_reg_masks[] = {
SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR), SMPL_REG(dsisr, PERF_REG_POWERPC_DSISR),
SMPL_REG(sier, PERF_REG_POWERPC_SIER), SMPL_REG(sier, PERF_REG_POWERPC_SIER),
SMPL_REG(mmcra, PERF_REG_POWERPC_MMCRA), SMPL_REG(mmcra, PERF_REG_POWERPC_MMCRA),
SMPL_REG(mmcr0, PERF_REG_POWERPC_MMCR0),
SMPL_REG(mmcr1, PERF_REG_POWERPC_MMCR1),
SMPL_REG(mmcr2, PERF_REG_POWERPC_MMCR2),
SMPL_REG_END SMPL_REG_END
}; };
@ -163,3 +172,43 @@ int arch_sdt_arg_parse_op(char *old_op, char **new_op)
return SDT_ARG_VALID; return SDT_ARG_VALID;
} }
uint64_t arch__intr_reg_mask(void)
{
struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
.sample_type = PERF_SAMPLE_REGS_INTR,
.precise_ip = 1,
.disabled = 1,
.exclude_kernel = 1,
};
int fd;
u32 version;
u64 extended_mask = 0, mask = PERF_REGS_MASK;
/*
* Get the PVR value to set the extended
* mask specific to platform.
*/
version = (((mfspr(SPRN_PVR)) >> 16) & 0xFFFF);
if (version == PVR_POWER9)
extended_mask = PERF_REG_PMU_MASK_300;
else
return mask;
attr.sample_regs_intr = extended_mask;
attr.sample_period = 1;
event_attr_init(&attr);
/*
* check if the pmu supports perf extended regs, before
* returning the register mask to sample.
*/
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd != -1) {
close(fd);
mask |= extended_mask;
}
return mask;
}

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PERF_UTIL_HEADER_H
#define __PERF_UTIL_HEADER_H
#include <linux/stringify.h>
#define mfspr(rn) ({unsigned long rval; \
asm volatile("mfspr %0," __stringify(rn) \
: "=r" (rval)); rval; })
#define SPRN_PVR 0x11F /* Processor Version Register */
#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF) /* Version field */
#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF) /* Revison field */
#endif /* __PERF_UTIL_HEADER_H */