]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf/x86/intel/ds: Unconditionally drain PEBS DS when changing PEBS_DATA_CFG
authorKan Liang <kan.liang@linux.intel.com>
Tue, 19 Nov 2024 13:55:01 +0000 (05:55 -0800)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 2 Dec 2024 11:01:33 +0000 (12:01 +0100)
The PEBS kernel warnings can still be observed with the below case.

when the below commands are running in parallel for a while.

  while true;
  do
perf record --no-buildid -a --intr-regs=AX  \
    -e cpu/event=0xd0,umask=0x81/pp \
    -c 10003 -o /dev/null ./triad;
  done &

  while true;
  do
perf record -e 'cpu/mem-loads,ldlat=3/uP' -W -d -- ./dtlb
  done

The commit b752ea0c28e3 ("perf/x86/intel/ds: Flush PEBS DS when changing
PEBS_DATA_CFG") intends to flush the entire PEBS buffer before the
hardware is reprogrammed. However, it fails in the above case.

The first perf command utilizes the large PEBS, while the second perf
command only utilizes a single PEBS. When the second perf event is
added, only the n_pebs++. The intel_pmu_pebs_enable() is invoked after
intel_pmu_pebs_add(). So the cpuc->n_pebs == cpuc->n_large_pebs check in
the intel_pmu_drain_large_pebs() fails. The PEBS DS is not flushed.
The new PEBS event should not be taken into account when flushing the
existing PEBS DS.

The check is unnecessary here. Before the hardware is reprogrammed, all
the stale records must be drained unconditionally.

For single PEBS or PEBS-vi-pt, the DS must be empty. The drain_pebs()
can handle the empty case. There is no harm to unconditionally drain the
PEBS DS.

Fixes: b752ea0c28e3 ("perf/x86/intel/ds: Flush PEBS DS when changing PEBS_DATA_CFG")
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20241119135504.1463839-2-kan.liang@linux.intel.com
arch/x86/events/intel/ds.c

index 8afc4ad3cd16eb8039c75f89e5e44ead7db1fdb1..1a4b326ca2ce1d8fd4ecc008dcf15c0f7bbf5bd6 100644 (file)
@@ -1489,7 +1489,7 @@ void intel_pmu_pebs_enable(struct perf_event *event)
                         * hence we need to drain when changing said
                         * size.
                         */
-                       intel_pmu_drain_large_pebs(cpuc);
+                       intel_pmu_drain_pebs_buffer();
                        adaptive_pebs_record_size_update();
                        wrmsrl(MSR_PEBS_DATA_CFG, pebs_data_cfg);
                        cpuc->active_pebs_data_cfg = pebs_data_cfg;