Skip to content

Commit 2492e5a

Browse files
sandip4nIngo Molnar
authored andcommitted
perf/x86/amd/uncore: Prevent UMC counters from saturating
Unlike L3 and DF counters, UMC counters (PERF_CTRs) set the Overflow bit (bit 48) and saturate on overflow. A subsequent pmu->read() of the event reports an incorrect accumulated count as there is no difference between the previous and the current values of the counter. To avoid this, inspect the current counter value and proactively reset the corresponding PERF_CTR register on every pmu->read(). Combined with the periodic reads initiated by the hrtimer, the counters never get a chance saturate but the resolution reduces to 47 bits. Fixes: 25e5684 ("perf/x86/amd/uncore: Add memory controller support") Signed-off-by: Sandipan Das <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Reviewed-by: Song Liu <[email protected]> Acked-by: Peter Zijlstra <[email protected]> Link: https://lore.kernel.org/r/dee9c8af2c6d66814cf4c6224529c144c620cf2c.1744906694.git.sandipan.das@amd.com
1 parent e1ed37b commit 2492e5a

File tree

1 file changed

+34
-1
lines changed

1 file changed

+34
-1
lines changed

arch/x86/events/amd/uncore.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,39 @@ static void amd_uncore_umc_start(struct perf_event *event, int flags)
956956
perf_event_update_userpage(event);
957957
}
958958

959+
static void amd_uncore_umc_read(struct perf_event *event)
960+
{
961+
struct hw_perf_event *hwc = &event->hw;
962+
u64 prev, new, shift;
963+
s64 delta;
964+
965+
shift = COUNTER_SHIFT + 1;
966+
prev = local64_read(&hwc->prev_count);
967+
968+
/*
969+
* UMC counters do not have RDPMC assignments. Read counts directly
970+
* from the corresponding PERF_CTR.
971+
*/
972+
rdmsrl(hwc->event_base, new);
973+
974+
/*
975+
* Unlike the other uncore counters, UMC counters saturate and set the
976+
* Overflow bit (bit 48) on overflow. Since they do not roll over,
977+
* proactively reset the corresponding PERF_CTR when bit 47 is set so
978+
* that the counter never gets a chance to saturate.
979+
*/
980+
if (new & BIT_ULL(63 - COUNTER_SHIFT)) {
981+
wrmsrl(hwc->event_base, 0);
982+
local64_set(&hwc->prev_count, 0);
983+
} else {
984+
local64_set(&hwc->prev_count, new);
985+
}
986+
987+
delta = (new << shift) - (prev << shift);
988+
delta >>= shift;
989+
local64_add(delta, &event->count);
990+
}
991+
959992
static
960993
void amd_uncore_umc_ctx_scan(struct amd_uncore *uncore, unsigned int cpu)
961994
{
@@ -1034,7 +1067,7 @@ int amd_uncore_umc_ctx_init(struct amd_uncore *uncore, unsigned int cpu)
10341067
.del = amd_uncore_del,
10351068
.start = amd_uncore_umc_start,
10361069
.stop = amd_uncore_stop,
1037-
.read = amd_uncore_read,
1070+
.read = amd_uncore_umc_read,
10381071
.capabilities = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
10391072
.module = THIS_MODULE,
10401073
};

0 commit comments

Comments
 (0)