]> git.itanic.dy.fi Git - linux-stable/commitdiff
perf annotate-data: Update sample histogram for type
authorNamhyung Kim <namhyung@kernel.org>
Wed, 13 Dec 2023 00:13:17 +0000 (16:13 -0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Sun, 24 Dec 2023 01:39:42 +0000 (22:39 -0300)
The annotated_data_type__update_samples() to get histogram for data type
access.

It'll be called by perf annotate to show which fields in the data type
are accessed frequently.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
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-12-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/annotate-data.c
tools/perf/util/annotate-data.h
tools/perf/util/annotate.c

index 5269c6630e0452ec4136ea6199251fdb2c1326d0..868f52ccdb74c6bf2db3d5a2e5ba2b00c356a256 100644 (file)
@@ -13,6 +13,8 @@
 #include "debuginfo.h"
 #include "debug.h"
 #include "dso.h"
+#include "evsel.h"
+#include "evlist.h"
 #include "map.h"
 #include "map_symbol.h"
 #include "strbuf.h"
@@ -302,6 +304,44 @@ struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
        return result;
 }
 
+static int alloc_data_type_histograms(struct annotated_data_type *adt, int nr_entries)
+{
+       int i;
+       size_t sz = sizeof(struct type_hist);
+
+       sz += sizeof(struct type_hist_entry) * adt->self.size;
+
+       /* Allocate a table of pointers for each event */
+       adt->nr_histograms = nr_entries;
+       adt->histograms = calloc(nr_entries, sizeof(*adt->histograms));
+       if (adt->histograms == NULL)
+               return -ENOMEM;
+
+       /*
+        * Each histogram is allocated for the whole size of the type.
+        * TODO: Probably we can move the histogram to members.
+        */
+       for (i = 0; i < nr_entries; i++) {
+               adt->histograms[i] = zalloc(sz);
+               if (adt->histograms[i] == NULL)
+                       goto err;
+       }
+       return 0;
+
+err:
+       while (--i >= 0)
+               free(adt->histograms[i]);
+       free(adt->histograms);
+       return -ENOMEM;
+}
+
+static void delete_data_type_histograms(struct annotated_data_type *adt)
+{
+       for (int i = 0; i < adt->nr_histograms; i++)
+               free(adt->histograms[i]);
+       free(adt->histograms);
+}
+
 void annotated_data_type__tree_delete(struct rb_root *root)
 {
        struct annotated_data_type *pos;
@@ -312,7 +352,48 @@ void annotated_data_type__tree_delete(struct rb_root *root)
                rb_erase(node, root);
                pos = rb_entry(node, struct annotated_data_type, node);
                delete_members(&pos->self);
+               delete_data_type_histograms(pos);
                free(pos->self.type_name);
                free(pos);
        }
 }
+
+/**
+ * annotated_data_type__update_samples - Update histogram
+ * @adt: Data type to update
+ * @evsel: Event to update
+ * @offset: Offset in the type
+ * @nr_samples: Number of samples at this offset
+ * @period: Event count at this offset
+ *
+ * This function updates type histogram at @ofs for @evsel.  Samples are
+ * aggregated before calling this function so it can be called with more
+ * than one samples at a certain offset.
+ */
+int annotated_data_type__update_samples(struct annotated_data_type *adt,
+                                       struct evsel *evsel, int offset,
+                                       int nr_samples, u64 period)
+{
+       struct type_hist *h;
+
+       if (adt == NULL)
+               return 0;
+
+       if (adt->histograms == NULL) {
+               int nr = evsel->evlist->core.nr_entries;
+
+               if (alloc_data_type_histograms(adt, nr) < 0)
+                       return -1;
+       }
+
+       if (offset < 0 || offset >= adt->self.size)
+               return -1;
+
+       h = adt->histograms[evsel->core.idx];
+
+       h->nr_samples += nr_samples;
+       h->addr[offset].nr_samples += nr_samples;
+       h->period += period;
+       h->addr[offset].period += period;
+       return 0;
+}
index 33748222e6aa4d5300771963c3ca2cb9a60f935a..d2dc025b1934518bdcd81b9935011ea4583b745e 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/rbtree.h>
 #include <linux/types.h>
 
+struct evsel;
 struct map_symbol;
 
 /**
@@ -29,16 +30,42 @@ struct annotated_member {
        int size;
 };
 
+/**
+ * struct type_hist_entry - Histogram entry per offset
+ * @nr_samples: Number of samples
+ * @period: Count of event
+ */
+struct type_hist_entry {
+       int nr_samples;
+       u64 period;
+};
+
+/**
+ * struct type_hist - Type histogram for each event
+ * @nr_samples: Total number of samples in this data type
+ * @period: Total count of the event in this data type
+ * @offset: Array of histogram entry
+ */
+struct type_hist {
+       u64                     nr_samples;
+       u64                     period;
+       struct type_hist_entry  addr[];
+};
+
 /**
  * struct annotated_data_type - Data type to profile
  * @node: RB-tree node for dso->type_tree
  * @self: Actual type information
+ * @nr_histogram: Number of histogram entries
+ * @histograms: An array of pointers to histograms
  *
  * This represents a data type accessed by samples in the profile data.
  */
 struct annotated_data_type {
        struct rb_node node;
        struct annotated_member self;
+       int nr_histograms;
+       struct type_hist **histograms;
 };
 
 extern struct annotated_data_type unknown_type;
@@ -49,6 +76,11 @@ extern struct annotated_data_type unknown_type;
 struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
                                           int reg, int offset);
 
+/* Update type access histogram at the given offset */
+int annotated_data_type__update_samples(struct annotated_data_type *adt,
+                                       struct evsel *evsel, int offset,
+                                       int nr_samples, u64 period);
+
 /* Release all data type information in the tree */
 void annotated_data_type__tree_delete(struct rb_root *root);
 
@@ -61,6 +93,16 @@ find_data_type(struct map_symbol *ms __maybe_unused, u64 ip __maybe_unused,
        return NULL;
 }
 
+static inline int
+annotated_data_type__update_samples(struct annotated_data_type *adt __maybe_unused,
+                                   struct evsel *evsel __maybe_unused,
+                                   int offset __maybe_unused,
+                                   int nr_samples __maybe_unused,
+                                   u64 period __maybe_unused)
+{
+       return -1;
+}
+
 static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe_unused)
 {
 }
index 8673eac4b9df491ab084026ff2f39c8a022667d5..6747779ecef829e5dc4ea09b4a6c9b8ac7362c84 100644 (file)
@@ -3679,6 +3679,7 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
        struct disasm_line *dl;
        struct annotated_insn_loc loc;
        struct annotated_op_loc *op_loc;
+       struct annotated_data_type *mem_type;
        u64 ip = he->ip;
        int i;
 
@@ -3709,7 +3710,13 @@ struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
                if (!op_loc->mem_ref)
                        continue;
 
-               return find_data_type(ms, ip, op_loc->reg, op_loc->offset);
+               mem_type = find_data_type(ms, ip, op_loc->reg, op_loc->offset);
+
+               annotated_data_type__update_samples(mem_type, evsel,
+                                                   op_loc->offset,
+                                                   he->stat.nr_events,
+                                                   he->stat.period);
+               return mem_type;
        }
        return NULL;
 }