perf: Avoid the read if the count is already updated

[ Upstream commit 8ce939a0fa194939cc1f92dbd8bc1a7806e7d40a ]

The event may have been updated in the PMU-specific implementation,
e.g., Intel PEBS counters snapshotting. The common code should not
read and overwrite the value.

The PERF_SAMPLE_READ in the data->sample_type can be used to detect
whether the PMU-specific value is available. If yes, avoid the
pmu->read() in the common code. Add a new flag, skip_read, to track the
case.

Factor out a perf_pmu_read() to clean up the code.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20250121152303.3128733-3-kan.liang@linux.intel.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Peter Zijlstra (Intel)
2025-01-21 07:23:02 -08:00
committed by Greg Kroah-Hartman
parent f47d605c5e
commit 948664b92e
3 changed files with 24 additions and 18 deletions

View File

@@ -1016,7 +1016,13 @@ struct perf_output_handle {
struct perf_buffer *rb; struct perf_buffer *rb;
unsigned long wakeup; unsigned long wakeup;
unsigned long size; unsigned long size;
u64 aux_flags; union {
u64 flags; /* perf_output*() */
u64 aux_flags; /* perf_aux_output*() */
struct {
u64 skip_read : 1;
};
};
union { union {
void *addr; void *addr;
unsigned long head; unsigned long head;

View File

@@ -1163,6 +1163,12 @@ static void perf_assert_pmu_disabled(struct pmu *pmu)
WARN_ON_ONCE(*this_cpu_ptr(pmu->pmu_disable_count) == 0); WARN_ON_ONCE(*this_cpu_ptr(pmu->pmu_disable_count) == 0);
} }
static inline void perf_pmu_read(struct perf_event *event)
{
if (event->state == PERF_EVENT_STATE_ACTIVE)
event->pmu->read(event);
}
static void get_ctx(struct perf_event_context *ctx) static void get_ctx(struct perf_event_context *ctx)
{ {
refcount_inc(&ctx->refcount); refcount_inc(&ctx->refcount);
@@ -3397,8 +3403,7 @@ static void __perf_event_sync_stat(struct perf_event *event,
* we know the event must be on the current CPU, therefore we * we know the event must be on the current CPU, therefore we
* don't need to use it. * don't need to use it.
*/ */
if (event->state == PERF_EVENT_STATE_ACTIVE) perf_pmu_read(event);
event->pmu->read(event);
perf_event_update_time(event); perf_event_update_time(event);
@@ -4524,15 +4529,8 @@ static void __perf_event_read(void *info)
pmu->read(event); pmu->read(event);
for_each_sibling_event(sub, event) { for_each_sibling_event(sub, event)
if (sub->state == PERF_EVENT_STATE_ACTIVE) { perf_pmu_read(sub);
/*
* Use sibling's PMU rather than @event's since
* sibling could be on different (eg: software) PMU.
*/
sub->pmu->read(sub);
}
}
data->ret = pmu->commit_txn(pmu); data->ret = pmu->commit_txn(pmu);
@@ -7297,9 +7295,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
values[n++] = running; values[n++] = running;
if ((leader != event) && if ((leader != event) && !handle->skip_read)
(leader->state == PERF_EVENT_STATE_ACTIVE)) perf_pmu_read(leader);
leader->pmu->read(leader);
values[n++] = perf_event_count(leader); values[n++] = perf_event_count(leader);
if (read_format & PERF_FORMAT_ID) if (read_format & PERF_FORMAT_ID)
@@ -7312,9 +7309,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
for_each_sibling_event(sub, leader) { for_each_sibling_event(sub, leader) {
n = 0; n = 0;
if ((sub != event) && if ((sub != event) && !handle->skip_read)
(sub->state == PERF_EVENT_STATE_ACTIVE)) perf_pmu_read(sub);
sub->pmu->read(sub);
values[n++] = perf_event_count(sub); values[n++] = perf_event_count(sub);
if (read_format & PERF_FORMAT_ID) if (read_format & PERF_FORMAT_ID)
@@ -7369,6 +7365,9 @@ void perf_output_sample(struct perf_output_handle *handle,
{ {
u64 sample_type = data->type; u64 sample_type = data->type;
if (data->sample_flags & PERF_SAMPLE_READ)
handle->skip_read = 1;
perf_output_put(handle, *header); perf_output_put(handle, *header);
if (sample_type & PERF_SAMPLE_IDENTIFIER) if (sample_type & PERF_SAMPLE_IDENTIFIER)

View File

@@ -181,6 +181,7 @@ __perf_output_begin(struct perf_output_handle *handle,
handle->rb = rb; handle->rb = rb;
handle->event = event; handle->event = event;
handle->flags = 0;
have_lost = local_read(&rb->lost); have_lost = local_read(&rb->lost);
if (unlikely(have_lost)) { if (unlikely(have_lost)) {