]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf tools: Save cln_size header
authorRicky Ringler <ricky.ringler@proton.me>
Sat, 4 Apr 2026 01:16:56 +0000 (01:16 +0000)
committerNamhyung Kim <namhyung@kernel.org>
Mon, 6 Apr 2026 05:30:52 +0000 (22:30 -0700)
Store cacheline size during perf record in header, so that cacheline
size can be used for other features, like sort keys for perf report.

Testing example with feat enabled:

  $ perf record ./Example

  $ perf report --header-only | grep -C 3 cacheline
  CPU_DOMAIN_INFO info available, use -I to display
  e_machine : 62
  e_flags : 0
  cacheline size: 64
  missing features: TRACING_DATA BUILD_ID BRANCH_STACK GROUP_DESC AUXTRACE \
  STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA
  ========

[namhyung: Update the commit message and remove blank lines]
Signed-off-by: Ricky Ringler <ricky.ringler@proton.me>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/builtin-inject.c
tools/perf/util/env.h
tools/perf/util/header.c
tools/perf/util/header.h
tools/perf/util/sort.c

index 5b29f4296861148cc1cc03683cd4e52e538a69af..11ac7c8c4be3bca81ddef9c5cffbaf1bf981985b 100644 (file)
@@ -2134,6 +2134,7 @@ static bool keep_feat(struct perf_inject *inject, int feat)
        case HEADER_HYBRID_TOPOLOGY:
        case HEADER_PMU_CAPS:
        case HEADER_CPU_DOMAIN_INFO:
+       case HEADER_CLN_SIZE:
                return true;
        /* Information that can be updated */
        case HEADER_BUILD_ID:
index a4501cbca375fd642e8732166add7a516ed371ee..c7052ac1f8562c9c846d31de25d9b7c11ae59666 100644 (file)
@@ -112,6 +112,7 @@ struct perf_env {
        struct cpu_cache_level  *caches;
        struct cpu_domain_map   **cpu_domain;
        int                      caches_cnt;
+       unsigned int            cln_size;
        u32                     comp_ratio;
        u32                     comp_ver;
        u32                     comp_type;
index ad7d09a481bb35e92f9e8213ef6d45e6d1493f39..a3b7b796639b42c02cb37e97f664e53f1a45ccb6 100644 (file)
@@ -54,6 +54,7 @@
 #include "bpf-event.h"
 #include "bpf-utils.h"
 #include "clockid.h"
+#include "cacheline.h"
 
 #include <linux/ctype.h>
 #include <internal/lib.h>
@@ -1315,6 +1316,19 @@ out:
        return ret;
 }
 
+static int write_cln_size(struct feat_fd *ff,
+                      struct evlist *evlist __maybe_unused)
+{
+       int cln_size = cacheline_size();
+
+       if (!cln_size)
+               cln_size = DEFAULT_CACHELINE_SIZE;
+
+       ff->ph->env.cln_size = cln_size;
+
+       return do_write(ff, &cln_size, sizeof(cln_size));
+}
+
 static int write_stat(struct feat_fd *ff __maybe_unused,
                      struct evlist *evlist __maybe_unused)
 {
@@ -2278,6 +2292,11 @@ static void print_cache(struct feat_fd *ff, FILE *fp __maybe_unused)
        }
 }
 
+static void print_cln_size(struct feat_fd *ff, FILE *fp)
+{
+       fprintf(fp, "# cacheline size: %u\n", ff->ph->env.cln_size);
+}
+
 static void print_compressed(struct feat_fd *ff, FILE *fp)
 {
        fprintf(fp, "# compressed : %s, level = %d, ratio = %d\n",
@@ -3184,6 +3203,16 @@ out_free_caches:
        return -1;
 }
 
+static int process_cln_size(struct feat_fd *ff, void *data __maybe_unused)
+{
+       struct perf_env *env = &ff->ph->env;
+
+       if (do_read_u32(ff, &env->cln_size))
+               return -1;
+
+       return 0;
+}
+
 static int process_sample_time(struct feat_fd *ff, void *data __maybe_unused)
 {
        struct perf_session *session;
@@ -3797,6 +3826,7 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
        FEAT_OPR(PMU_CAPS,      pmu_caps,       false),
        FEAT_OPR(CPU_DOMAIN_INFO,       cpu_domain_info,        true),
        FEAT_OPR(E_MACHINE,     e_machine,      false),
+       FEAT_OPR(CLN_SIZE,      cln_size,       false),
 };
 
 struct header_print_data {
index 41ce663d93ff8ab2007512d3472af65c1863243a..86b1a72026d3f3469ff1bcb54c5a927d7b1b42ba 100644 (file)
@@ -55,6 +55,7 @@ enum {
        HEADER_PMU_CAPS,
        HEADER_CPU_DOMAIN_INFO,
        HEADER_E_MACHINE,
+       HEADER_CLN_SIZE,
        HEADER_LAST_FEATURE,
        HEADER_FEAT_BITS        = 256,
 };
@@ -206,6 +207,8 @@ int write_padded(struct feat_fd *fd, const void *bf,
 
 int build_caches_for_cpu(u32 cpu, struct cpu_cache_level caches[], u32 *cntp);
 
+#define DEFAULT_CACHELINE_SIZE 64
+
 /*
  * arch specific callback
  */
index fda8fcfa46e07d385f2934174317bcdf9d8bdaee..5c9656cc4f9dacdb66351543c103ddd3cee6860a 100644 (file)
@@ -31,6 +31,7 @@
 #include "time-utils.h"
 #include "cgroup.h"
 #include "machine.h"
+#include "session.h"
 #include "trace-event.h"
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -2584,7 +2585,26 @@ struct sort_entry sort_type_offset = {
 
 /* --sort typecln */
 
-#define DEFAULT_CACHELINE_SIZE 64
+static int
+hist_entry__cln_size(struct hist_entry *he)
+{
+       int ret = 0;
+
+       if (he && he->hists) {
+               struct evsel *evsel = hists_to_evsel(he->hists);
+
+               if (evsel) {
+                       struct perf_session *session = evsel__session(evsel);
+
+                       ret = session->header.env.cln_size;
+               }
+       }
+
+       if (ret < 1)
+               ret = DEFAULT_CACHELINE_SIZE; // avoid div/0 later
+
+       return ret;
+}
 
 static int64_t
 sort__typecln_sort(struct hist_entry *left, struct hist_entry *right)
@@ -2592,11 +2612,9 @@ sort__typecln_sort(struct hist_entry *left, struct hist_entry *right)
        struct annotated_data_type *left_type = left->mem_type;
        struct annotated_data_type *right_type = right->mem_type;
        int64_t left_cln, right_cln;
+       int64_t cln_size_left = hist_entry__cln_size(left);
+       int64_t cln_size_right = hist_entry__cln_size(right);
        int64_t ret;
-       int cln_size = cacheline_size();
-
-       if (cln_size == 0)
-               cln_size = DEFAULT_CACHELINE_SIZE;
 
        if (!left_type) {
                sort__type_init(left);
@@ -2612,8 +2630,8 @@ sort__typecln_sort(struct hist_entry *left, struct hist_entry *right)
        if (ret)
                return ret;
 
-       left_cln = left->mem_type_off / cln_size;
-       right_cln = right->mem_type_off / cln_size;
+       left_cln = left->mem_type_off / cln_size_left;
+       right_cln = right->mem_type_off / cln_size_right;
        return left_cln - right_cln;
 }
 
@@ -2621,10 +2639,7 @@ static int hist_entry__typecln_snprintf(struct hist_entry *he, char *bf,
                                     size_t size, unsigned int width __maybe_unused)
 {
        struct annotated_data_type *he_type = he->mem_type;
-       int cln_size = cacheline_size();
-
-       if (cln_size == 0)
-               cln_size = DEFAULT_CACHELINE_SIZE;
+       int cln_size = hist_entry__cln_size(he);
 
        return repsep_snprintf(bf, size, "%s: cache-line %d", he_type->self.type_name,
                               he->mem_type_off / cln_size);