diff options
author | Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | 2013-12-12 11:54:57 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-12-16 08:37:59 -0500 |
commit | 443e802bab16916f9a51a34f2213f4dee6e8762c (patch) | |
tree | 8481d35917b96ad1dfee837e52ad804e3459e018 | |
parent | 443d4beb823d4dccaaf964b59df9dd38b4d6aae7 (diff) |
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 <brueckner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/perf_event.h | 6 | ||||
-rw-r--r-- | arch/s390/kernel/perf_cpum_sf.c | 20 | ||||
-rw-r--r-- | arch/s390/kernel/perf_event.c | 25 |
3 files changed, 50 insertions, 1 deletions
diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h index 99d7f4e333c2..7667bde37dcb 100644 --- a/arch/s390/include/asm/perf_event.h +++ b/arch/s390/include/asm/perf_event.h | |||
@@ -42,6 +42,12 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs); | |||
42 | extern unsigned long perf_misc_flags(struct pt_regs *regs); | 42 | extern unsigned long perf_misc_flags(struct pt_regs *regs); |
43 | #define perf_misc_flags(regs) perf_misc_flags(regs) | 43 | #define perf_misc_flags(regs) perf_misc_flags(regs) |
44 | 44 | ||
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 | |||
45 | /* Perf PMU definitions for the counter facility */ | 51 | /* Perf PMU definitions for the counter facility */ |
46 | #define PERF_CPUM_CF_MAX_CTR 256 | 52 | #define PERF_CPUM_CF_MAX_CTR 256 |
47 | 53 | ||
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index 3ab7e67ee2e4..d611facae599 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c | |||
@@ -840,6 +840,7 @@ static int perf_push_sample(struct perf_event *event, | |||
840 | { | 840 | { |
841 | int overflow; | 841 | int overflow; |
842 | struct pt_regs regs; | 842 | struct pt_regs regs; |
843 | struct perf_sf_sde_regs *sde_regs; | ||
843 | struct perf_sample_data data; | 844 | struct perf_sample_data data; |
844 | 845 | ||
845 | /* Skip samples that are invalid or for which the instruction address | 846 | /* Skip samples that are invalid or for which the instruction address |
@@ -850,7 +851,16 @@ static int perf_push_sample(struct perf_event *event, | |||
850 | 851 | ||
851 | perf_sample_data_init(&data, 0, event->hw.last_period); | 852 | perf_sample_data_init(&data, 0, event->hw.last_period); |
852 | 853 | ||
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 | */ | ||
853 | memset(®s, 0, sizeof(regs)); | 859 | memset(®s, 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 *) ®s.int_parm_long; | ||
863 | |||
854 | regs.psw.addr = sample->ia; | 864 | regs.psw.addr = sample->ia; |
855 | if (sample->T) | 865 | if (sample->T) |
856 | regs.psw.mask |= PSW_MASK_DAT; | 866 | regs.psw.mask |= PSW_MASK_DAT; |
@@ -873,6 +883,16 @@ static int perf_push_sample(struct perf_event *event, | |||
873 | break; | 883 | break; |
874 | } | 884 | } |
875 | 885 | ||
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 | |||
876 | overflow = 0; | 896 | overflow = 0; |
877 | if (perf_event_overflow(event, &data, ®s)) { | 897 | if (perf_event_overflow(event, &data, ®s)) { |
878 | overflow = 1; | 898 | overflow = 1; |
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index 3bd2bf030ad4..60a68261d091 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Performance event support for s390x | 2 | * Performance event support for s390x |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2012 | 4 | * Copyright IBM Corp. 2012, 2013 |
5 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | 5 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * 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) | |||
89 | : PERF_RECORD_MISC_GUEST_KERNEL; | 89 | : PERF_RECORD_MISC_GUEST_KERNEL; |
90 | } | 90 | } |
91 | 91 | ||
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 *) ®s->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 | |||
92 | unsigned long perf_misc_flags(struct pt_regs *regs) | 107 | unsigned long perf_misc_flags(struct pt_regs *regs) |
93 | { | 108 | { |
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 | |||
94 | if (is_in_guest(regs)) | 117 | if (is_in_guest(regs)) |
95 | return perf_misc_guest_flags(regs); | 118 | return perf_misc_guest_flags(regs); |
96 | 119 | ||