]> git.itanic.dy.fi Git - linux-stable/commitdiff
perf report: Add 'typeoff' sort key
authorNamhyung Kim <namhyung@kernel.org>
Wed, 13 Dec 2023 00:13:18 +0000 (16:13 -0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Sun, 24 Dec 2023 01:39:42 +0000 (22:39 -0300)
The typeoff sort key shows the data type name, offset and the name of
the field.  This is useful to see which field in the struct is accessed
most frequently.

  $ perf report -s type,typeoff --hierarchy --stdio
  ...
  #     Overhead  Data Type / Data Type Offset
  # ............  ............................
  #
  ...
        1.23%     struct cfs_rq
           0.19%    struct cfs_rq +404 (throttle_count)
           0.19%    struct cfs_rq +0 (load.weight)
           0.19%    struct cfs_rq +336 (leaf_cfs_rq_list.next)
           0.09%    struct cfs_rq +272 (propagate)
           0.09%    struct cfs_rq +196 (removed.nr)
           0.09%    struct cfs_rq +80 (curr)
           0.09%    struct cfs_rq +544 (lt_b_children_throttled)
           0.06%    struct cfs_rq +320 (rq)

Committer testing:

Again with the perf.data from the previous csets:

  # perf report --stdio -s type,typeoff
  # To display the perf.data header info, please use --header/--header-only options.
  #
  #
  # Total Lost Samples: 0
  #
  # Samples: 4  of event 'cpu_atom/mem-loads,ldlat=30/P'
  # Event count (approx.): 7
  #
  # Overhead  Data Type  Data Type Offset
  # ........  .........  ................
  #
      42.86%  struct list_head  struct list_head +8 (prev)
      42.86%  (unknown)  (unknown) +0 (no field)
      14.29%  char       char +0 (no field)

  #
  # (Tip: To see callchains in a more compact form: perf report -g folded)
  #
  # perf report --stdio -s dso,type,typeoff
  # To display the perf.data header info, please use --header/--header-only options.
  #
  #
  # Total Lost Samples: 0
  #
  # Samples: 4  of event 'cpu_atom/mem-loads,ldlat=30/P'
  # Event count (approx.): 7
  #
  # Overhead  Shared Object         Data Type  Data Type Offset
  # ........  ....................  .........  ................
  #
      42.86%  [kernel.kallsyms]     struct list_head  struct list_head +8 (prev)
      28.57%  libc.so.6             (unknown)  (unknown) +0 (no field)
      14.29%  [kernel.kallsyms]     char       char +0 (no field)
      14.29%  ld-linux-x86-64.so.2  (unknown)  (unknown) +0 (no field)

  #
  # (Tip: If you have debuginfo enabled, try: perf report -s sym,srcline)
  #
  #

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: linux-toolchains@vger.kernel.org
Cc: linux-trace-devel@vger.kernel.org
Link: https://lore.kernel.org/r/20231213001323.718046-13-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-report.txt
tools/perf/util/annotate.c
tools/perf/util/hist.h
tools/perf/util/sort.c
tools/perf/util/sort.h

index aec34417090b0cfd6df90b8b1a94dea842fdabd9..b57eb51b47aa642dad3f58af945d57e1e98baab6 100644 (file)
@@ -119,6 +119,7 @@ OPTIONS
          to the previous instruction in cycles. And currently supported only on X86
        - simd: Flags describing a SIMD operation. "e" for empty Arm SVE predicate. "p" for partial Arm SVE predicate
        - type: Data type of sample memory access.
+       - typeoff: Offset in the data type of sample memory access.
 
        By default, comm, dso and symbol keys are used.
        (i.e. --sort comm,dso,symbol)
index 6747779ecef829e5dc4ea09b4a6c9b8ac7362c84..f966e8f83c5ecd13f42f6f7604b6c548e2fe7c16 100644 (file)
@@ -3716,6 +3716,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
                                                    op_loc->offset,
                                                    he->stat.nr_events,
                                                    he->stat.period);
+               he->mem_type_off = op_loc->offset;
                return mem_type;
        }
        return NULL;
index 7ebbf427b1eacda664038ee851e5aaec38d25c80..18128a49309efa6b8da72bc9e154a8f619657194 100644 (file)
@@ -83,6 +83,7 @@ enum hist_column {
        HISTC_ADDR,
        HISTC_SIMD,
        HISTC_TYPE,
+       HISTC_TYPE_OFFSET,
        HISTC_NR_COLS, /* Last entry */
 };
 
index a41209e242ae423719d091b2e8a5475c2d0e94d2..d78e680d398809745d4a14dc43f965c839763e44 100644 (file)
@@ -2153,8 +2153,10 @@ static void sort__type_init(struct hist_entry *he)
                return;
 
        he->mem_type = hist_entry__get_data_type(he);
-       if (he->mem_type == NULL)
+       if (he->mem_type == NULL) {
                he->mem_type = &unknown_type;
+               he->mem_type_off = 0;
+       }
 }
 
 static int64_t
@@ -2198,6 +2200,84 @@ struct sort_entry sort_type = {
        .se_width_idx   = HISTC_TYPE,
 };
 
+/* --sort typeoff */
+
+static int64_t
+sort__typeoff_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 ret;
+
+       if (!left_type) {
+               sort__type_init(left);
+               left_type = left->mem_type;
+       }
+
+       if (!right_type) {
+               sort__type_init(right);
+               right_type = right->mem_type;
+       }
+
+       ret = strcmp(left_type->self.type_name, right_type->self.type_name);
+       if (ret)
+               return ret;
+       return left->mem_type_off - right->mem_type_off;
+}
+
+static void fill_member_name(char *buf, size_t sz, struct annotated_member *m,
+                            int offset, bool first)
+{
+       struct annotated_member *child;
+
+       if (list_empty(&m->children))
+               return;
+
+       list_for_each_entry(child, &m->children, node) {
+               if (child->offset <= offset && offset < child->offset + child->size) {
+                       int len = 0;
+
+                       /* It can have anonymous struct/union members */
+                       if (child->var_name) {
+                               len = scnprintf(buf, sz, "%s%s",
+                                               first ? "" : ".", child->var_name);
+                               first = false;
+                       }
+
+                       fill_member_name(buf + len, sz - len, child, offset, first);
+                       return;
+               }
+       }
+}
+
+static int hist_entry__typeoff_snprintf(struct hist_entry *he, char *bf,
+                                    size_t size, unsigned int width __maybe_unused)
+{
+       struct annotated_data_type *he_type = he->mem_type;
+       char buf[4096];
+
+       buf[0] = '\0';
+       if (list_empty(&he_type->self.children))
+               snprintf(buf, sizeof(buf), "no field");
+       else
+               fill_member_name(buf, sizeof(buf), &he_type->self,
+                                he->mem_type_off, true);
+       buf[4095] = '\0';
+
+       return repsep_snprintf(bf, size, "%s %+d (%s)", he_type->self.type_name,
+                              he->mem_type_off, buf);
+}
+
+struct sort_entry sort_type_offset = {
+       .se_header      = "Data Type Offset",
+       .se_cmp         = sort__type_cmp,
+       .se_collapse    = sort__typeoff_sort,
+       .se_sort        = sort__typeoff_sort,
+       .se_init        = sort__type_init,
+       .se_snprintf    = hist_entry__typeoff_snprintf,
+       .se_width_idx   = HISTC_TYPE_OFFSET,
+};
+
 
 struct sort_dimension {
        const char              *name;
@@ -2254,6 +2334,7 @@ static struct sort_dimension common_sort_dimensions[] = {
        DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc),
        DIM(SORT_SIMD, "simd", sort_simd),
        DIM(SORT_ANNOTATE_DATA_TYPE, "type", sort_type),
+       DIM(SORT_ANNOTATE_DATA_TYPE_OFFSET, "typeoff", sort_type_offset),
 };
 
 #undef DIM
index aabf0b8331a359d2e56db2cbf2741e8e033185de..d806adcc1e1eadc287e18cd526bcb78babaa0a54 100644 (file)
@@ -113,6 +113,7 @@ struct hist_entry {
        u64                     p_stage_cyc;
        u8                      cpumode;
        u8                      depth;
+       int                     mem_type_off;
        struct simd_flags       simd_flags;
 
        /* We are added by hists__add_dummy_entry. */
@@ -247,6 +248,7 @@ enum sort_type {
        SORT_GLOBAL_RETIRE_LAT,
        SORT_SIMD,
        SORT_ANNOTATE_DATA_TYPE,
+       SORT_ANNOTATE_DATA_TYPE_OFFSET,
 
        /* branch stack specific sort keys */
        __SORT_BRANCH_STACK,