s390/cpum_sf: Filter perf events based event->attr.exclude_* settings
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Thu, 12 Dec 2013 17:05:20 +0000 (18:05 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 16 Dec 2013 13:37:59 +0000 (14:37 +0100)
Introduce the perf_exclude_event() function to filter perf samples
according to event->attr.exclude_* settings.   During event initialization,
reset event exclude settings that are not supported.

Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/kernel/perf_cpum_sf.c

index d611facae59990757b954b52a8d5f9d85dcad76b..28fa2f235158857bfc3b1d07e9339ba2ed1b45d8 100644 (file)
@@ -723,10 +723,19 @@ static int cpumsf_pmu_event_init(struct perf_event *event)
                return -ENOENT;
        }
 
+       /* Check online status of the CPU to which the event is pinned */
        if (event->cpu >= nr_cpumask_bits ||
            (event->cpu >= 0 && !cpu_online(event->cpu)))
                return -ENODEV;
 
+       /* Force reset of idle/hv excludes regardless of what the
+        * user requested.
+        */
+       if (event->attr.exclude_hv)
+               event->attr.exclude_hv = 0;
+       if (event->attr.exclude_idle)
+               event->attr.exclude_idle = 0;
+
        err = __hw_perf_event_init(event);
        if (unlikely(err))
                if (event->destroy)
@@ -824,6 +833,29 @@ static void cpumsf_pmu_disable(struct pmu *pmu)
        cpuhw->flags &= ~PMU_F_ENABLED;
 }
 
+/* perf_exclude_event() - Filter event
+ * @event:     The perf event
+ * @regs:      pt_regs structure
+ * @sde_regs:  Sample-data-entry (sde) regs structure
+ *
+ * Filter perf events according to their exclude specification.
+ *
+ * Return non-zero if the event shall be excluded.
+ */
+static int perf_exclude_event(struct perf_event *event, struct pt_regs *regs,
+                             struct perf_sf_sde_regs *sde_regs)
+{
+       if (event->attr.exclude_user && user_mode(regs))
+               return 1;
+       if (event->attr.exclude_kernel && !user_mode(regs))
+               return 1;
+       if (event->attr.exclude_guest && sde_regs->in_guest)
+               return 1;
+       if (event->attr.exclude_host && !sde_regs->in_guest)
+               return 1;
+       return 0;
+}
+
 /* perf_push_sample() - Push samples to perf
  * @event:     The perf event
  * @sample:    Hardware sample data
@@ -894,12 +926,14 @@ static int perf_push_sample(struct perf_event *event,
                sde_regs->in_guest = 1;
 
        overflow = 0;
+       if (perf_exclude_event(event, &regs, sde_regs))
+               goto out;
        if (perf_event_overflow(event, &data, &regs)) {
                overflow = 1;
                event->pmu->stop(event, 0);
        }
        perf_event_update_userpage(event);
-
+out:
        return overflow;
 }