mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 20:53:53 +08:00
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: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Peter 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.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
af5bb4ed12
commit
66d219014a
@ -905,26 +905,6 @@ static void pt_buffer_free_aux(void *data)
|
||||
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
|
||||
*/
|
||||
@ -989,20 +969,33 @@ void intel_pt_interrupt(void)
|
||||
|
||||
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_buffer *buf = perf_get_aux(&pt->handle);
|
||||
struct pt_buffer *buf;
|
||||
|
||||
if (!buf || pt_buffer_is_full(buf, pt)) {
|
||||
event->hw.state = PERF_HES_STOPPED;
|
||||
return;
|
||||
buf = perf_aux_output_begin(&pt->handle, event);
|
||||
if (!buf)
|
||||
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;
|
||||
event->hw.state = 0;
|
||||
hwc->state = 0;
|
||||
|
||||
pt_config_buffer(buf->cur->table, buf->cur_idx,
|
||||
buf->output_off);
|
||||
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)
|
||||
@ -1035,19 +1028,7 @@ static void pt_event_stop(struct perf_event *event, int mode)
|
||||
pt_handle_status(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)
|
||||
pt->handle.head =
|
||||
local_xchg(&buf->data_size,
|
||||
@ -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)
|
||||
{
|
||||
struct pt_buffer *buf;
|
||||
struct pt *pt = this_cpu_ptr(&pt_ctx);
|
||||
struct hw_perf_event *hwc = &event->hw;
|
||||
int ret = -EBUSY;
|
||||
@ -1067,34 +1052,18 @@ static int pt_event_add(struct perf_event *event, int mode)
|
||||
if (pt->handle.event)
|
||||
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) {
|
||||
pt_event_start(event, 0);
|
||||
ret = -EBUSY;
|
||||
ret = -EINVAL;
|
||||
if (hwc->state == PERF_HES_STOPPED)
|
||||
goto fail_end_stop;
|
||||
goto fail;
|
||||
} else {
|
||||
hwc->state = PERF_HES_STOPPED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_end_stop:
|
||||
perf_aux_output_end(&pt->handle, 0, true);
|
||||
fail_stop:
|
||||
hwc->state = PERF_HES_STOPPED;
|
||||
ret = 0;
|
||||
fail:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user