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:
committed by
Greg Kroah-Hartman
parent
f47d605c5e
commit
948664b92e
@@ -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;
|
||||||
|
@@ -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)
|
||||||
|
@@ -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)) {
|
||||||
|
Reference in New Issue
Block a user