Skip to content

Commit 0349164

Browse files
committed
perf: Avoid the read if the count is already updated
JIRA: https://issues.redhat.com/browse/RHEL-47444 upstream ======== commit 8ce939a Author: Peter Zijlstra (Intel) <peterz@infradead.org> Date: Tue Jan 21 07:23:02 2025 -0800 description =========== 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: Michael Petlan <mpetlan@redhat.com>
1 parent f8df957 commit 0349164

File tree

3 files changed

+24
-18
lines changed

3 files changed

+24
-18
lines changed

include/linux/perf_event.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,13 @@ struct perf_output_handle {
10411041
struct perf_buffer *rb;
10421042
unsigned long wakeup;
10431043
unsigned long size;
1044-
u64 aux_flags;
1044+
union {
1045+
u64 flags; /* perf_output*() */
1046+
u64 aux_flags; /* perf_aux_output*() */
1047+
struct {
1048+
u64 skip_read : 1;
1049+
};
1050+
};
10451051
union {
10461052
void *addr;
10471053
unsigned long head;

kernel/events/core.c

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,12 @@ static void perf_assert_pmu_disabled(struct pmu *pmu)
11951195
WARN_ON_ONCE(*this_cpu_ptr(pmu->pmu_disable_count) == 0);
11961196
}
11971197

1198+
static inline void perf_pmu_read(struct perf_event *event)
1199+
{
1200+
if (event->state == PERF_EVENT_STATE_ACTIVE)
1201+
event->pmu->read(event);
1202+
}
1203+
11981204
static void get_ctx(struct perf_event_context *ctx)
11991205
{
12001206
refcount_inc(&ctx->refcount);
@@ -3473,8 +3479,7 @@ static void __perf_event_sync_stat(struct perf_event *event,
34733479
* we know the event must be on the current CPU, therefore we
34743480
* don't need to use it.
34753481
*/
3476-
if (event->state == PERF_EVENT_STATE_ACTIVE)
3477-
event->pmu->read(event);
3482+
perf_pmu_read(event);
34783483

34793484
perf_event_update_time(event);
34803485

@@ -4624,15 +4629,8 @@ static void __perf_event_read(void *info)
46244629

46254630
pmu->read(event);
46264631

4627-
for_each_sibling_event(sub, event) {
4628-
if (sub->state == PERF_EVENT_STATE_ACTIVE) {
4629-
/*
4630-
* Use sibling's PMU rather than @event's since
4631-
* sibling could be on different (eg: software) PMU.
4632-
*/
4633-
sub->pmu->read(sub);
4634-
}
4635-
}
4632+
for_each_sibling_event(sub, event)
4633+
perf_pmu_read(sub);
46364634

46374635
data->ret = pmu->commit_txn(pmu);
46384636

@@ -7399,9 +7397,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
73997397
if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
74007398
values[n++] = running;
74017399

7402-
if ((leader != event) &&
7403-
(leader->state == PERF_EVENT_STATE_ACTIVE))
7404-
leader->pmu->read(leader);
7400+
if ((leader != event) && !handle->skip_read)
7401+
perf_pmu_read(leader);
74057402

74067403
values[n++] = perf_event_count(leader, self);
74077404
if (read_format & PERF_FORMAT_ID)
@@ -7414,9 +7411,8 @@ static void perf_output_read_group(struct perf_output_handle *handle,
74147411
for_each_sibling_event(sub, leader) {
74157412
n = 0;
74167413

7417-
if ((sub != event) &&
7418-
(sub->state == PERF_EVENT_STATE_ACTIVE))
7419-
sub->pmu->read(sub);
7414+
if ((sub != event) && !handle->skip_read)
7415+
perf_pmu_read(sub);
74207416

74217417
values[n++] = perf_event_count(sub, self);
74227418
if (read_format & PERF_FORMAT_ID)
@@ -7475,6 +7471,9 @@ void perf_output_sample(struct perf_output_handle *handle,
74757471
{
74767472
u64 sample_type = data->type;
74777473

7474+
if (data->sample_flags & PERF_SAMPLE_READ)
7475+
handle->skip_read = 1;
7476+
74787477
perf_output_put(handle, *header);
74797478

74807479
if (sample_type & PERF_SAMPLE_IDENTIFIER)

kernel/events/ring_buffer.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ __perf_output_begin(struct perf_output_handle *handle,
185185

186186
handle->rb = rb;
187187
handle->event = event;
188+
handle->flags = 0;
188189

189190
have_lost = local_read(&rb->lost);
190191
if (unlikely(have_lost)) {

0 commit comments

Comments
 (0)