]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf env: Find correct branch counter info on hybrid
authorKan Liang <kan.liang@linux.intel.com>
Mon, 9 Sep 2024 18:42:00 +0000 (11:42 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 11 Sep 2024 16:08:46 +0000 (13:08 -0300)
No event is printed in the "Branch Counter" column on hybrid machines.

For example,

  $ perf record -e "{cpu_core/branch-instructions/pp,cpu_core/branches/}:S" -j any,counter
  $ perf report --total-cycles

  # Branch counter abbr list:
  # cpu_core/branch-instructions/pp = A
  # cpu_core/branches/ = B
  # '-' No event occurs
  # '+' Event occurrences may be lost due to branch counter saturated
  #
  # Sampled Cycles%  Sampled Cycles  Avg Cycles%  Avg Cycles  Branch Counter
  # ...............  ..............  ...........  ..........  ..............
            44.54%          727.1K        0.00%           1   |+   |+   |
            36.31%          592.7K        0.00%           2   |+   |+   |
            17.83%          291.1K        0.00%           1   |+   |+   |

The branch counter information (br_cntr_width and br_cntr_nr) in the
perf_env is retrieved from the CPU_PMU_CAPS. However, the CPU_PMU_CAPS
is not available on hybrid machines. Without the width information, the
number of occurrences of an event cannot be calculated.

For a hybrid machine, the caps information should be retrieved from the
PMU_CAPS, and stored in the perf_env->pmu_caps.

Add a perf_env__find_br_cntr_info() to return the correct branch counter
information from the corresponding fields.

Committer notes:

While testing I couldn't s ee those "Branch counter" columns enabled by
pressing 'B' on the TUI, after reporting it to the list Kan explained
the situation:

<quote Kan Liang>
For a hybrid client, the "Branch Counter" feature is only supported
starting from the just released Lunar Lake. Perf falls back to only
"ANY" on your Raptor Lake.

The "The branch counter is not available" message is expected.

Here is the 'perf evlist' result from my Lunar Lake machine,

  # perf evlist -v
  cpu_core/branch-instructions/pp: type: 4 (cpu_core), size: 136, config: 0xc4 (branch-instructions), { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|READ|PERIOD|BRANCH_STACK|IDENTIFIER, read_format: ID|GROUP|LOST, disabled: 1, freq: 1, enable_on_exec: 1, precise_ip: 2, sample_id_all: 1, exclude_guest: 1, branch_sample_type: ANY|COUNTERS
  #
</quote>

Fixes: 6f9d8d1de2c61288 ("perf script: Add branch counters")
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240909184201.553519-1-kan.liang@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-script.c
tools/perf/util/annotate.c
tools/perf/util/env.c
tools/perf/util/env.h
tools/perf/util/session.c

index dbe792b52c5cbc82c10de5f1a66c0754997e747e..a644787fa9e1dc257f329c29cb94faa6056e0e1e 100644 (file)
@@ -1241,10 +1241,11 @@ static int ip__fprintf_jump(uint64_t ip, struct branch_entry *en,
        }
 
        if (PRINT_FIELD(BRCNTR)) {
-               unsigned int width = evsel__env(evsel)->br_cntr_width;
-               unsigned int i = 0, j, num, mask = (1L << width) - 1;
                struct evsel *pos = evsel__leader(evsel);
+               unsigned int i = 0, j, num, mask, width;
 
+               perf_env__find_br_cntr_info(evsel__env(evsel), NULL, &width);
+               mask = (1L << width) - 1;
                printed += fprintf(fp, "br_cntr: ");
                evlist__for_each_entry_from(evsel->evlist, pos) {
                        if (!(pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS))
index 1a347a711dcf5c62d0b625e24e2dfa22ac5dd9b7..37ce43c4eb8f6952b110c957890d12afaa134317 100644 (file)
@@ -333,14 +333,15 @@ static int symbol__account_br_cntr(struct annotated_branch *branch,
 {
        unsigned int br_cntr_nr = evsel__leader(evsel)->br_cntr_nr;
        unsigned int base = evsel__leader(evsel)->br_cntr_idx;
-       unsigned int width = evsel__env(evsel)->br_cntr_width;
        unsigned int off = offset * evsel->evlist->nr_br_cntr;
-       unsigned int i, mask = (1L << width) - 1;
        u64 *branch_br_cntr = branch->br_cntr;
+       unsigned int i, mask, width;
 
        if (!br_cntr || !branch_br_cntr)
                return 0;
 
+       perf_env__find_br_cntr_info(evsel__env(evsel), NULL, &width);
+       mask = (1L << width) - 1;
        for (i = 0; i < br_cntr_nr; i++) {
                u64 cntr = (br_cntr >> i * width) & mask;
 
index a459374d0a1a1dc89721e210616cfe201f01789d..1edbccfc3281d2b17df19eb8884e3d8772cbc470 100644 (file)
@@ -624,3 +624,18 @@ out:
        free(cap_eq);
        return NULL;
 }
+
+void perf_env__find_br_cntr_info(struct perf_env *env,
+                                unsigned int *nr,
+                                unsigned int *width)
+{
+       if (nr) {
+               *nr = env->cpu_pmu_caps ? env->br_cntr_nr :
+                                         env->pmu_caps->br_cntr_nr;
+       }
+
+       if (width) {
+               *width = env->cpu_pmu_caps ? env->br_cntr_width :
+                                            env->pmu_caps->br_cntr_width;
+       }
+}
index 2a2c37cc40b7828ef8a92624e1d885ed9a326fc9..51b36c36019be666650eb8f3a3764ee9e54812a7 100644 (file)
@@ -192,4 +192,7 @@ char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
                             const char *cap);
 
 bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name);
+void perf_env__find_br_cntr_info(struct perf_env *env,
+                                unsigned int *nr,
+                                unsigned int *width);
 #endif /* __PERF_ENV_H */
index b492300ec959ecc2615bd0aaae874967325f343e..dbaf07bf6c5fb88ced03b8ef03338cb67732f044 100644 (file)
@@ -856,7 +856,6 @@ static void branch_stack__printf(struct perf_sample *sample,
        struct branch_entry *entries = perf_sample__branch_entries(sample);
        bool callstack = evsel__has_branch_callstack(evsel);
        u64 *branch_stack_cntr = sample->branch_stack_cntr;
-       struct perf_env *env = evsel__env(evsel);
        uint64_t i;
 
        if (!callstack) {
@@ -900,8 +899,11 @@ static void branch_stack__printf(struct perf_sample *sample,
        }
 
        if (branch_stack_cntr) {
+               unsigned int br_cntr_width, br_cntr_nr;
+
+               perf_env__find_br_cntr_info(evsel__env(evsel), &br_cntr_nr, &br_cntr_width);
                printf("... branch stack counters: nr:%" PRIu64 " (counter width: %u max counter nr:%u)\n",
-                       sample->branch_stack->nr, env->br_cntr_width, env->br_cntr_nr);
+                       sample->branch_stack->nr, br_cntr_width, br_cntr_nr);
                for (i = 0; i < sample->branch_stack->nr; i++)
                        printf("..... %2"PRIu64": %016" PRIx64 "\n", i, branch_stack_cntr[i]);
        }