Commit 66d21901 authored by Alexander Shishkin's avatar Alexander Shishkin Committed by Ingo Molnar

perf/x86/intel/pt: Move transaction start/stop to PMU start/stop callbacks

As per AUX buffer management requirement, AUX output has to happen between
pmu::start and pmu::stop calls so that perf_event_stop() actually stops it
and therefore perf can free the AUX data after it has called pmu::stop.

This patch moves perf_aux_output_{begin,end} from pt_event_{add,del} to
pt_event_{start,stop}. As a bonus, we get rid of pt_buffer_is_full(),
which is already taken care of by perf_aux_output_begin() anyway.
Signed-off-by: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Cc: vince@deater.net
Link: http://lkml.kernel.org/r/1457098969-21595-5-git-send-email-alexander.shishkin@linux.intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent af5bb4ed
...@@ -905,26 +905,6 @@ static void pt_buffer_free_aux(void *data) ...@@ -905,26 +905,6 @@ static void pt_buffer_free_aux(void *data)
kfree(buf); kfree(buf);
} }
/**
* pt_buffer_is_full() - check if the buffer is full
* @buf: PT buffer.
* @pt: Per-cpu pt handle.
*
* If the user hasn't read data from the output region that aux_head
* points to, the buffer is considered full: the user needs to read at
* least this region and update aux_tail to point past it.
*/
static bool pt_buffer_is_full(struct pt_buffer *buf, struct pt *pt)
{
if (buf->snapshot)
return false;
if (local_read(&buf->data_size) >= pt->handle.size)
return true;
return false;
}
/** /**
* intel_pt_interrupt() - PT PMI handler * intel_pt_interrupt() - PT PMI handler
*/ */
...@@ -989,20 +969,33 @@ void intel_pt_interrupt(void) ...@@ -989,20 +969,33 @@ void intel_pt_interrupt(void)
static void pt_event_start(struct perf_event *event, int mode) static void pt_event_start(struct perf_event *event, int mode)
{ {
struct hw_perf_event *hwc = &event->hw;
struct pt *pt = this_cpu_ptr(&pt_ctx); struct pt *pt = this_cpu_ptr(&pt_ctx);
struct pt_buffer *buf = perf_get_aux(&pt->handle); struct pt_buffer *buf;
if (!buf || pt_buffer_is_full(buf, pt)) { buf = perf_aux_output_begin(&pt->handle, event);
event->hw.state = PERF_HES_STOPPED; if (!buf)
return; goto fail_stop;
pt_buffer_reset_offsets(buf, pt->handle.head);
if (!buf->snapshot) {
if (pt_buffer_reset_markers(buf, &pt->handle))
goto fail_end_stop;
} }
ACCESS_ONCE(pt->handle_nmi) = 1; ACCESS_ONCE(pt->handle_nmi) = 1;
event->hw.state = 0; hwc->state = 0;
pt_config_buffer(buf->cur->table, buf->cur_idx, pt_config_buffer(buf->cur->table, buf->cur_idx,
buf->output_off); buf->output_off);
pt_config(event); pt_config(event);
return;
fail_end_stop:
perf_aux_output_end(&pt->handle, 0, true);
fail_stop:
hwc->state = PERF_HES_STOPPED;
} }
static void pt_event_stop(struct perf_event *event, int mode) static void pt_event_stop(struct perf_event *event, int mode)
...@@ -1035,19 +1028,7 @@ static void pt_event_stop(struct perf_event *event, int mode) ...@@ -1035,19 +1028,7 @@ static void pt_event_stop(struct perf_event *event, int mode)
pt_handle_status(pt); pt_handle_status(pt);
pt_update_head(pt); pt_update_head(pt);
}
}
static void pt_event_del(struct perf_event *event, int mode)
{
struct pt *pt = this_cpu_ptr(&pt_ctx);
struct pt_buffer *buf;
pt_event_stop(event, PERF_EF_UPDATE);
buf = perf_get_aux(&pt->handle);
if (buf) {
if (buf->snapshot) if (buf->snapshot)
pt->handle.head = pt->handle.head =
local_xchg(&buf->data_size, local_xchg(&buf->data_size,
...@@ -1057,9 +1038,13 @@ static void pt_event_del(struct perf_event *event, int mode) ...@@ -1057,9 +1038,13 @@ static void pt_event_del(struct perf_event *event, int mode)
} }
} }
static void pt_event_del(struct perf_event *event, int mode)
{
pt_event_stop(event, PERF_EF_UPDATE);
}
static int pt_event_add(struct perf_event *event, int mode) static int pt_event_add(struct perf_event *event, int mode)
{ {
struct pt_buffer *buf;
struct pt *pt = this_cpu_ptr(&pt_ctx); struct pt *pt = this_cpu_ptr(&pt_ctx);
struct hw_perf_event *hwc = &event->hw; struct hw_perf_event *hwc = &event->hw;
int ret = -EBUSY; int ret = -EBUSY;
...@@ -1067,34 +1052,18 @@ static int pt_event_add(struct perf_event *event, int mode) ...@@ -1067,34 +1052,18 @@ static int pt_event_add(struct perf_event *event, int mode)
if (pt->handle.event) if (pt->handle.event)
goto fail; goto fail;
buf = perf_aux_output_begin(&pt->handle, event);
ret = -EINVAL;
if (!buf)
goto fail_stop;
pt_buffer_reset_offsets(buf, pt->handle.head);
if (!buf->snapshot) {
ret = pt_buffer_reset_markers(buf, &pt->handle);
if (ret)
goto fail_end_stop;
}
if (mode & PERF_EF_START) { if (mode & PERF_EF_START) {
pt_event_start(event, 0); pt_event_start(event, 0);
ret = -EBUSY; ret = -EINVAL;
if (hwc->state == PERF_HES_STOPPED) if (hwc->state == PERF_HES_STOPPED)
goto fail_end_stop; goto fail;
} else { } else {
hwc->state = PERF_HES_STOPPED; hwc->state = PERF_HES_STOPPED;
} }
return 0; ret = 0;
fail_end_stop:
perf_aux_output_end(&pt->handle, 0, true);
fail_stop:
hwc->state = PERF_HES_STOPPED;
fail: fail:
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment