From fdf6335838eea8921cdc42c290327513419b5b82 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 22 Oct 2020 10:23:17 +0800 Subject: [PATCH 2205/2944] Intel: perf/x86: Fix n_metric for cancelled txn to #31064126 commit 3dbde69575637658d2094ee4416c21bc22eb89fe upstream Backport summary: backport to kernel 4.19.57 for ICX perf topdown support When a group that has TopDown members is failed to be scheduled, any later TopDown groups will not return valid values. Here is an example. A background perf that occupies all the GP counters and the fixed counter 1. $perf stat -e "{cycles,cycles,cycles,cycles,cycles,cycles,cycles, cycles,cycles}:D" -a A user monitors a TopDown group. It works well, because the fixed counter 3 and the PERF_METRICS are available. $perf stat -x, --topdown -- ./workload retiring,bad speculation,frontend bound,backend bound, 18.0,16.1,40.4,25.5, Then the user tries to monitor a group that has TopDown members. Because of the cycles event, the group is failed to be scheduled. $perf stat -x, -e '{slots,topdown-retiring,topdown-be-bound, topdown-fe-bound,topdown-bad-spec,cycles}' -- ./workload ,,slots,0,0.00,, ,,topdown-retiring,0,0.00,, ,,topdown-be-bound,0,0.00,, ,,topdown-fe-bound,0,0.00,, ,,topdown-bad-spec,0,0.00,, ,,cycles,0,0.00,, The user tries to monitor a TopDown group again. It doesn't work anymore. $perf stat -x, --topdown -- ./workload ,,,,, In a txn, cancel_txn() is to truncate the event_list for a canceled group and update the number of events added in this transaction. However, the number of TopDown events added in this transaction is not updated. The kernel will probably fail to add new Topdown events. Fixes: 7b2c05a15d29 ("perf/x86/intel: Generic support for hardware TopDown metrics") Reported-by: Andi Kleen Reported-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Tested-by: Kan Liang Link: https://lkml.kernel.org/r/20201005082611.GH2628@hirez.programming.kicks-ass.net Signed-off-by: Yunying Sun Signed-off-by: Peng Wang Reviewed-by: Artie Ding --- arch/x86/events/core.c | 3 +++ arch/x86/events/perf_event.h | 1 + 2 files changed, 4 insertions(+) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index bb0c419..2e23168 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1015,6 +1015,7 @@ static int add_nr_metric_event(struct cpu_hw_events *cpuc, if (cpuc->n_metric == INTEL_TD_METRIC_NUM) return -EINVAL; cpuc->n_metric++; + cpuc->n_txn_metric++; } return 0; @@ -1953,6 +1954,7 @@ static void x86_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) perf_pmu_disable(pmu); __this_cpu_write(cpu_hw_events.n_txn, 0); + __this_cpu_write(cpu_hw_events.n_txn_metric, 0); } /* @@ -1978,6 +1980,7 @@ static void x86_pmu_cancel_txn(struct pmu *pmu) */ __this_cpu_sub(cpu_hw_events.n_added, __this_cpu_read(cpu_hw_events.n_txn)); __this_cpu_sub(cpu_hw_events.n_events, __this_cpu_read(cpu_hw_events.n_txn)); + __this_cpu_sub(cpu_hw_events.n_metric, __this_cpu_read(cpu_hw_events.n_txn_metric)); perf_pmu_enable(pmu); } diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 83ee24a..363e581 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -220,6 +220,7 @@ struct cpu_hw_events { they've never been enabled yet */ int n_txn; /* the # last events in the below arrays; added in the current transaction */ + int n_txn_metric; int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */ u64 tags[X86_PMC_IDX_MAX]; -- 1.8.3.1