perf/x86/intel/ds: Fix the conversion from TSC to perf time
Commit Message
From: Kan Liang <kan.liang@linux.intel.com>
The time order is incorrect when the TSC in a PEBS record is used.
$perf record -e cycles:upp dd if=/dev/zero of=/dev/null
count=10000
$ perf script --show-task-events
perf-exec 0 0.000000: PERF_RECORD_COMM: perf-exec:915/915
dd 915 106.479872: PERF_RECORD_COMM exec: dd:915/915
dd 915 106.483270: PERF_RECORD_EXIT(915:915):(914:914)
dd 915 106.512429: 1 cycles:upp:
ffffffff96c011b7 [unknown] ([unknown])
... ...
The perf time is from sched_clock_cpu(). The current PEBS code
unconditionally convert the TSC to native_sched_clock(). There is a
shift between the two clocks. If the TSC is stable, the shift is
consistent, __sched_clock_offset. If the TSC is unstable, the shift has
to be calculated at runtime.
The TSC unstable case seems to be some corner cases (e.g., due to broken
BIOS). This patch doesn't support the conversion when the TSC is
unstable. The TSC in a PEBS record will be dropped and fallback to the
software perf time provided by the generic code.
Fixes: 47a3aeb39e8d ("perf/x86/intel/pebs: Fix PEBS timestamps overwritten")
Reported-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/all/CAM9d7cgWDVAq8-11RbJ2uGfwkKD6fA-OMwOKDrNUrU_=8MgEjg@mail.gmail.com/
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
---
arch/x86/events/intel/ds.c | 36 +++++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
Comments
On Mon, Jan 23, 2023 at 09:20:27AM -0800, kan.liang@linux.intel.com wrote:
> The TSC unstable case seems to be some corner cases (e.g., due to broken
> BIOS). This patch doesn't support the conversion when the TSC is
> unstable. The TSC in a PEBS record will be dropped and fallback to the
> software perf time provided by the generic code.
:-(
You're saying there's modern systems (PEBS timestamps are fairly new)
that trigger unstable TSC ?
What systems in specific have you observed this on -- we really need to
name and shame them, this is fully unacceptable.
On 2023-01-23 3:39 p.m., Peter Zijlstra wrote:
> On Mon, Jan 23, 2023 at 09:20:27AM -0800, kan.liang@linux.intel.com wrote:
>> The TSC unstable case seems to be some corner cases (e.g., due to broken
>> BIOS). This patch doesn't support the conversion when the TSC is
>> unstable. The TSC in a PEBS record will be dropped and fallback to the
>> software perf time provided by the generic code.
>
> :-(
>
> You're saying there's modern systems (PEBS timestamps are fairly new)
> that trigger unstable TSC ?
>
> What systems in specific have you observed this on -- we really need to
> name and shame them, this is fully unacceptable.
No, I didn't observe any systems which trigger unstable TSC.
Here, I tried to explain the reason why the patch didn't support the
conversion when the TSC is unstable. Because it's a corner case and very
unlikely to happen.
The "broken BIOS" case is quoted from the __sched_clock_work(), which
shows that the broken BIOS may be a reason of unstable TSC.
Sorry for the confusion caused.
Let me rephrase this.
"This patch doesn't support the conversion when the TSC is unstable.
Because the TSC unstable case is a corner case and very unlikely to
happen. Even if it happens, the TSC in a PEBS record will be dropped and
fall back to the inaccurate software perf time provided by the generic
code as perf does it on the previous platforms."
Thanks,
Kan
@@ -2,12 +2,14 @@
#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/slab.h>
+#include <linux/sched/clock.h>
#include <asm/cpu_entry_area.h>
#include <asm/perf_event.h>
#include <asm/tlbflush.h>
#include <asm/insn.h>
#include <asm/io.h>
+#include <asm/timer.h>
#include "../perf_event.h"
@@ -1568,6 +1570,28 @@ static u64 get_data_src(struct perf_event *event, u64 aux)
return val;
}
+static void setup_pebs_time(struct perf_event *event,
+ struct perf_sample_data *data,
+ u64 tsc)
+{
+ /* Converting to a user-defined clock is not supported yet. */
+ if (event->attr.use_clockid != 0)
+ return;
+
+ /*
+ * Converting the TSC to perf time is only supported,
+ * when the TSC is stable.
+ * The TSC unstable case seems to be some corner cases
+ * (e.g., due to broken BIOS). Drop the PEBS TSC and
+ * fall back to the SW time, see perf_event_clock().
+ */
+ if (!using_native_sched_clock() || !sched_clock_stable())
+ return;
+
+ data->time = native_sched_clock_from_tsc(tsc) + __sched_clock_offset;
+ data->sample_flags |= PERF_SAMPLE_TIME;
+}
+
#define PERF_SAMPLE_ADDR_TYPE (PERF_SAMPLE_ADDR | \
PERF_SAMPLE_PHYS_ADDR | \
PERF_SAMPLE_DATA_PAGE_SIZE)
@@ -1715,11 +1739,8 @@ static void setup_pebs_fixed_sample_data(struct perf_event *event,
*
* We can only do this for the default trace clock.
*/
- if (x86_pmu.intel_cap.pebs_format >= 3 &&
- event->attr.use_clockid == 0) {
- data->time = native_sched_clock_from_tsc(pebs->tsc);
- data->sample_flags |= PERF_SAMPLE_TIME;
- }
+ if (x86_pmu.intel_cap.pebs_format >= 3)
+ setup_pebs_time(event, data, pebs->tsc);
if (has_branch_stack(event))
perf_sample_save_brstack(data, event, &cpuc->lbr_stack);
@@ -1781,10 +1802,7 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event,
perf_sample_data_init(data, 0, event->hw.last_period);
data->period = event->hw.last_period;
- if (event->attr.use_clockid == 0) {
- data->time = native_sched_clock_from_tsc(basic->tsc);
- data->sample_flags |= PERF_SAMPLE_TIME;
- }
+ setup_pebs_time(event, data, basic->tsc);
/*
* We must however always use iregs for the unwinder to stay sane; the