From: Adrian Hunter <adrian.hun...@intel.com>

[ Upstream commit 20aa39708a5999b7921b27482a756766272286ac ]

The code assumed a change in cycle count means accurate IPC. That is not
correct, for example when sampling both branches and instructions, or at
a FUP packet (which is not CYC-eligible) address. Fix by using an explicit
flag to indicate when IPC can be sampled.

Fixes: 5b1dc0fd1da06 ("perf intel-pt: Add support for samples to contain IPC 
ratio")
Signed-off-by: Adrian Hunter <adrian.hun...@intel.com>
Reviewed-by: Andi Kleen <a...@linux.intel.com>
Cc: Jiri Olsa <jo...@redhat.com>
Cc: linux-kernel@vger.kernel.org
Link: https://lore.kernel.org/r/20210205175350.23817-3-adrian.hun...@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 .../util/intel-pt-decoder/intel-pt-decoder.c     | 11 ++++++++++-
 .../util/intel-pt-decoder/intel-pt-decoder.h     |  1 +
 tools/perf/util/intel-pt.c                       | 16 ++++++----------
 3 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c 
b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index a3fdea49ad663..7f53b63088b2c 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -2637,9 +2637,18 @@ const struct intel_pt_state *intel_pt_decode(struct 
intel_pt_decoder *decoder)
                }
                if (intel_pt_sample_time(decoder->pkt_state)) {
                        intel_pt_update_sample_time(decoder);
-                       if (decoder->sample_cyc)
+                       if (decoder->sample_cyc) {
                                decoder->sample_tot_cyc_cnt = 
decoder->tot_cyc_cnt;
+                               decoder->state.flags |= INTEL_PT_SAMPLE_IPC;
+                               decoder->sample_cyc = false;
+                       }
                }
+               /*
+                * When using only TSC/MTC to compute cycles, IPC can be
+                * sampled as soon as the cycle count changes.
+                */
+               if (!decoder->have_cyc)
+                       decoder->state.flags |= INTEL_PT_SAMPLE_IPC;
        }
 
        decoder->state.timestamp = decoder->sample_timestamp;
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h 
b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
index e289e463d635e..7396da0fa3a7c 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
@@ -17,6 +17,7 @@
 #define INTEL_PT_ABORT_TX      (1 << 1)
 #define INTEL_PT_ASYNC         (1 << 2)
 #define INTEL_PT_FUP_IP                (1 << 3)
+#define INTEL_PT_SAMPLE_IPC    (1 << 4)
 
 enum intel_pt_sample_type {
        INTEL_PT_BRANCH         = 1 << 0,
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 8aeaeba48a41f..d0e0ce11faf58 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -1304,7 +1304,8 @@ static int intel_pt_synth_branch_sample(struct 
intel_pt_queue *ptq)
                sample.branch_stack = (struct branch_stack *)&dummy_bs;
        }
 
-       sample.cyc_cnt = ptq->ipc_cyc_cnt - ptq->last_br_cyc_cnt;
+       if (ptq->state->flags & INTEL_PT_SAMPLE_IPC)
+               sample.cyc_cnt = ptq->ipc_cyc_cnt - ptq->last_br_cyc_cnt;
        if (sample.cyc_cnt) {
                sample.insn_cnt = ptq->ipc_insn_cnt - ptq->last_br_insn_cnt;
                ptq->last_br_insn_cnt = ptq->ipc_insn_cnt;
@@ -1366,7 +1367,8 @@ static int intel_pt_synth_instruction_sample(struct 
intel_pt_queue *ptq)
        sample.stream_id = ptq->pt->instructions_id;
        sample.period = ptq->state->tot_insn_cnt - ptq->last_insn_cnt;
 
-       sample.cyc_cnt = ptq->ipc_cyc_cnt - ptq->last_in_cyc_cnt;
+       if (ptq->state->flags & INTEL_PT_SAMPLE_IPC)
+               sample.cyc_cnt = ptq->ipc_cyc_cnt - ptq->last_in_cyc_cnt;
        if (sample.cyc_cnt) {
                sample.insn_cnt = ptq->ipc_insn_cnt - ptq->last_in_insn_cnt;
                ptq->last_in_insn_cnt = ptq->ipc_insn_cnt;
@@ -1901,14 +1903,8 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
 
        ptq->have_sample = false;
 
-       if (ptq->state->tot_cyc_cnt > ptq->ipc_cyc_cnt) {
-               /*
-                * Cycle count and instruction count only go together to create
-                * a valid IPC ratio when the cycle count changes.
-                */
-               ptq->ipc_insn_cnt = ptq->state->tot_insn_cnt;
-               ptq->ipc_cyc_cnt = ptq->state->tot_cyc_cnt;
-       }
+       ptq->ipc_insn_cnt = ptq->state->tot_insn_cnt;
+       ptq->ipc_cyc_cnt = ptq->state->tot_cyc_cnt;
 
        /*
         * Do PEBS first to allow for the possibility that the PEBS timestamp
-- 
2.27.0



Reply via email to