s390/cpum_sf: Detect KVM guest samples
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Thu, 12 Dec 2013 16:54:57 +0000 (17:54 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 16 Dec 2013 13:37:59 +0000 (14:37 +0100)
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>
arch/s390/include/asm/perf_event.h
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/perf_event.c

index 99d7f4e333c2c835cfe3d3ebaae5a972e700e6d4..7667bde37dcb50ecb0f8705294cb3a07137fddad 100644 (file)
@@ -42,6 +42,12 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
 extern unsigned long perf_misc_flags(struct pt_regs *regs);
 #define perf_misc_flags(regs) perf_misc_flags(regs)
 
+/* Perf pt_regs extension for sample-data-entry indicators */
+struct perf_sf_sde_regs {
+       unsigned char in_guest:1;         /* guest sample */
+       unsigned long reserved:63;        /* reserved */
+};
+
 /* Perf PMU definitions for the counter facility */
 #define PERF_CPUM_CF_MAX_CTR           256
 
index 3ab7e67ee2e435a534bc0dde75b6f941a6f6604e..d611facae59990757b954b52a8d5f9d85dcad76b 100644 (file)
@@ -840,6 +840,7 @@ static int perf_push_sample(struct perf_event *event,
 {
        int overflow;
        struct pt_regs regs;
+       struct perf_sf_sde_regs *sde_regs;
        struct perf_sample_data data;
 
        /* Skip samples that are invalid or for which the instruction address
@@ -850,7 +851,16 @@ static int perf_push_sample(struct perf_event *event,
 
        perf_sample_data_init(&data, 0, event->hw.last_period);
 
+       /* Setup pt_regs to look like an CPU-measurement external interrupt
+        * using the Program Request Alert code.  The regs.int_parm_long
+        * field which is unused contains additional sample-data-entry related
+        * indicators.
+        */
        memset(&regs, 0, sizeof(regs));
+       regs.int_code = 0x1407;
+       regs.int_parm = CPU_MF_INT_SF_PRA;
+       sde_regs = (struct perf_sf_sde_regs *) &regs.int_parm_long;
+
        regs.psw.addr = sample->ia;
        if (sample->T)
                regs.psw.mask |= PSW_MASK_DAT;
@@ -873,6 +883,16 @@ static int perf_push_sample(struct perf_event *event,
                break;
        }
 
+       /* The host-program-parameter (hpp) contains the sie control
+        * block that is set by sie64a() in entry64.S.  Check if hpp
+        * refers to a valid control block and set sde_regs flags
+        * accordingly.  This would allow to use hpp values for other
+        * purposes too.
+        * For now, simply use a non-zero value as guest indicator.
+        */
+       if (sample->hpp)
+               sde_regs->in_guest = 1;
+
        overflow = 0;
        if (perf_event_overflow(event, &data, &regs)) {
                overflow = 1;
index 3bd2bf030ad444a39b1c99afed90b4b2ba2c3ef1..60a68261d09192dd6e03b4767670b709869c3f11 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Performance event support for s390x
  *
- *  Copyright IBM Corp. 2012
+ *  Copyright IBM Corp. 2012, 2013
  *  Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  *
  * 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)
                                        : PERF_RECORD_MISC_GUEST_KERNEL;
 }
 
+static unsigned long perf_misc_flags_sf(struct pt_regs *regs)
+{
+       struct perf_sf_sde_regs *sde_regs;
+       unsigned long flags;
+
+       sde_regs = (struct perf_sf_sde_regs *) &regs->int_parm_long;
+       if (sde_regs->in_guest)
+               flags = user_mode(regs) ? PERF_RECORD_MISC_GUEST_USER
+                                       : PERF_RECORD_MISC_GUEST_KERNEL;
+       else
+               flags = user_mode(regs) ? PERF_RECORD_MISC_USER
+                                       : PERF_RECORD_MISC_KERNEL;
+       return flags;
+}
+
 unsigned long perf_misc_flags(struct pt_regs *regs)
 {
+       /* Check if the cpum_sf PMU has created the pt_regs structure.
+        * In this case, perf misc flags can be easily extracted.  Otherwise,
+        * do regular checks on the pt_regs content.
+        */
+       if (regs->int_code == 0x1407 && regs->int_parm == CPU_MF_INT_SF_PRA)
+               if (!regs->gprs[15])
+                       return perf_misc_flags_sf(regs);
+
        if (is_in_guest(regs))
                return perf_misc_guest_flags(regs);