Skip to content

Commit 443e802

Browse files
hbruecknerMartin Schwidefsky
authored andcommitted
s390/cpum_sf: Detect KVM guest samples
The host-program-parameter (hpp) value of basic sample-data-entries designates a SIE control block that is set by the LPP instruction in sie64a(). Non-zero values indicate guest samples, a value of zero indicates a host sample. For perf samples, host and guest samples are distinguished using particular PERF_MISC_* flags. The perf layer calls perf_misc_flags() to set the flags based on the pt_regs content. For each sample-data-entry, the cpum_sf PMU creates a pt_regs structure with the sample-data information. An additional flag structure is added to easily distinguish between host and guest samples. Signed-off-by: Hendrik Brueckner <[email protected]> Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent 443d4be commit 443e802

File tree

3 files changed

+50
-1
lines changed

3 files changed

+50
-1
lines changed

arch/s390/include/asm/perf_event.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
4242
extern unsigned long perf_misc_flags(struct pt_regs *regs);
4343
#define perf_misc_flags(regs) perf_misc_flags(regs)
4444

45+
/* Perf pt_regs extension for sample-data-entry indicators */
46+
struct perf_sf_sde_regs {
47+
unsigned char in_guest:1; /* guest sample */
48+
unsigned long reserved:63; /* reserved */
49+
};
50+
4551
/* Perf PMU definitions for the counter facility */
4652
#define PERF_CPUM_CF_MAX_CTR 256
4753

arch/s390/kernel/perf_cpum_sf.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ static int perf_push_sample(struct perf_event *event,
840840
{
841841
int overflow;
842842
struct pt_regs regs;
843+
struct perf_sf_sde_regs *sde_regs;
843844
struct perf_sample_data data;
844845

845846
/* Skip samples that are invalid or for which the instruction address
@@ -850,7 +851,16 @@ static int perf_push_sample(struct perf_event *event,
850851

851852
perf_sample_data_init(&data, 0, event->hw.last_period);
852853

854+
/* Setup pt_regs to look like an CPU-measurement external interrupt
855+
* using the Program Request Alert code. The regs.int_parm_long
856+
* field which is unused contains additional sample-data-entry related
857+
* indicators.
858+
*/
853859
memset(&regs, 0, sizeof(regs));
860+
regs.int_code = 0x1407;
861+
regs.int_parm = CPU_MF_INT_SF_PRA;
862+
sde_regs = (struct perf_sf_sde_regs *) &regs.int_parm_long;
863+
854864
regs.psw.addr = sample->ia;
855865
if (sample->T)
856866
regs.psw.mask |= PSW_MASK_DAT;
@@ -873,6 +883,16 @@ static int perf_push_sample(struct perf_event *event,
873883
break;
874884
}
875885

886+
/* The host-program-parameter (hpp) contains the sie control
887+
* block that is set by sie64a() in entry64.S. Check if hpp
888+
* refers to a valid control block and set sde_regs flags
889+
* accordingly. This would allow to use hpp values for other
890+
* purposes too.
891+
* For now, simply use a non-zero value as guest indicator.
892+
*/
893+
if (sample->hpp)
894+
sde_regs->in_guest = 1;
895+
876896
overflow = 0;
877897
if (perf_event_overflow(event, &data, &regs)) {
878898
overflow = 1;

arch/s390/kernel/perf_event.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Performance event support for s390x
33
*
4-
* Copyright IBM Corp. 2012
4+
* Copyright IBM Corp. 2012, 2013
55
* Author(s): Hendrik Brueckner <[email protected]>
66
*
77
* This program is free software; you can redistribute it and/or modify
@@ -89,8 +89,31 @@ static unsigned long perf_misc_guest_flags(struct pt_regs *regs)
8989
: PERF_RECORD_MISC_GUEST_KERNEL;
9090
}
9191

92+
static unsigned long perf_misc_flags_sf(struct pt_regs *regs)
93+
{
94+
struct perf_sf_sde_regs *sde_regs;
95+
unsigned long flags;
96+
97+
sde_regs = (struct perf_sf_sde_regs *) &regs->int_parm_long;
98+
if (sde_regs->in_guest)
99+
flags = user_mode(regs) ? PERF_RECORD_MISC_GUEST_USER
100+
: PERF_RECORD_MISC_GUEST_KERNEL;
101+
else
102+
flags = user_mode(regs) ? PERF_RECORD_MISC_USER
103+
: PERF_RECORD_MISC_KERNEL;
104+
return flags;
105+
}
106+
92107
unsigned long perf_misc_flags(struct pt_regs *regs)
93108
{
109+
/* Check if the cpum_sf PMU has created the pt_regs structure.
110+
* In this case, perf misc flags can be easily extracted. Otherwise,
111+
* do regular checks on the pt_regs content.
112+
*/
113+
if (regs->int_code == 0x1407 && regs->int_parm == CPU_MF_INT_SF_PRA)
114+
if (!regs->gprs[15])
115+
return perf_misc_flags_sf(regs);
116+
94117
if (is_in_guest(regs))
95118
return perf_misc_guest_flags(regs);
96119

0 commit comments

Comments
 (0)