perf/x86/intel/pt: Add sampling support
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>
Fri, 25 Oct 2019 14:08:35 +0000 (17:08 +0300)
committerIngo Molnar <mingo@kernel.org>
Wed, 13 Nov 2019 10:06:16 +0000 (11:06 +0100)
Add AUX sampling support to the PT PMU: implement an NMI-safe callback
that takes a snapshot of the buffer without touching the event states.
This is done for PT events that don't use PMIs, that is, snapshot mode
(RO mapping of the AUX area).

Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Cc: adrian.hunter@intel.com
Cc: mathieu.poirier@linaro.org
Link: https://lkml.kernel.org/r/20191025140835.53665-4-alexander.shishkin@linux.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/events/intel/pt.c

index 170f3b4022749c1a4e90f2c83ad556c2342bf0b8..2f20d5a333c1a423a565ad342fe8f7ea6ad8abfc 100644 (file)
@@ -1208,6 +1208,13 @@ pt_buffer_setup_aux(struct perf_event *event, void **pages,
        if (!nr_pages)
                return NULL;
 
+       /*
+        * Only support AUX sampling in snapshot mode, where we don't
+        * generate NMIs.
+        */
+       if (event->attr.aux_sample_size && !snapshot)
+               return NULL;
+
        if (cpu == -1)
                cpu = raw_smp_processor_id();
        node = cpu_to_node(cpu);
@@ -1506,6 +1513,52 @@ static void pt_event_stop(struct perf_event *event, int mode)
        }
 }
 
+static long pt_event_snapshot_aux(struct perf_event *event,
+                                 struct perf_output_handle *handle,
+                                 unsigned long size)
+{
+       struct pt *pt = this_cpu_ptr(&pt_ctx);
+       struct pt_buffer *buf = perf_get_aux(&pt->handle);
+       unsigned long from = 0, to;
+       long ret;
+
+       if (WARN_ON_ONCE(!buf))
+               return 0;
+
+       /*
+        * Sampling is only allowed on snapshot events;
+        * see pt_buffer_setup_aux().
+        */
+       if (WARN_ON_ONCE(!buf->snapshot))
+               return 0;
+
+       /*
+        * Here, handle_nmi tells us if the tracing is on
+        */
+       if (READ_ONCE(pt->handle_nmi))
+               pt_config_stop(event);
+
+       pt_read_offset(buf);
+       pt_update_head(pt);
+
+       to = local_read(&buf->data_size);
+       if (to < size)
+               from = buf->nr_pages << PAGE_SHIFT;
+       from += to - size;
+
+       ret = perf_output_copy_aux(&pt->handle, handle, from, to);
+
+       /*
+        * If the tracing was on when we turned up, restart it.
+        * Compiler barrier not needed as we couldn't have been
+        * preempted by anything that touches pt->handle_nmi.
+        */
+       if (pt->handle_nmi)
+               pt_config_start(event);
+
+       return ret;
+}
+
 static void pt_event_del(struct perf_event *event, int mode)
 {
        pt_event_stop(event, PERF_EF_UPDATE);
@@ -1625,6 +1678,7 @@ static __init int pt_init(void)
        pt_pmu.pmu.del                   = pt_event_del;
        pt_pmu.pmu.start                 = pt_event_start;
        pt_pmu.pmu.stop                  = pt_event_stop;
+       pt_pmu.pmu.snapshot_aux          = pt_event_snapshot_aux;
        pt_pmu.pmu.read                  = pt_event_read;
        pt_pmu.pmu.setup_aux             = pt_buffer_setup_aux;
        pt_pmu.pmu.free_aux              = pt_buffer_free_aux;