]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf hist: Basic support for mem_stat accounting
authorNamhyung Kim <namhyung@kernel.org>
Wed, 30 Apr 2025 20:55:42 +0000 (13:55 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 2 May 2025 18:36:14 +0000 (15:36 -0300)
Add a logic to account he->mem_stat based on mem_stat_type in hists.

Each mem_stat entry will have different meaning based on the type so the
index in the array is calculated at runtime using the corresponding
value in the sample.data_src.

Still hists has no mem_stat_types yet so this code won't work for now.

Later hists->mem_stat_types will be allocated based on what users want
in the output actually.

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: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Link: https://lore.kernel.org/r/20250430205548.789750-6-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/ui/hist.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/mem-events.c
tools/perf/util/mem-events.h
tools/perf/util/sort.c

index ec44633207aa3abaa370ba9853b0b77a81ea60a4..2aad46bbd2ed4d93405a83479d660d9c726facd8 100644 (file)
@@ -11,6 +11,7 @@
 #include "../util/sort.h"
 #include "../util/evsel.h"
 #include "../util/evlist.h"
+#include "../util/mem-events.h"
 #include "../util/thread.h"
 #include "../util/util.h"
 
@@ -500,6 +501,12 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
        return 0;
 }
 
+static bool perf_hpp__is_mem_stat_entry(struct perf_hpp_fmt *fmt)
+{
+       (void)fmt;
+       return false;
+}
+
 static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a)
 {
        return a->header == hpp__header_fn;
@@ -1022,3 +1029,35 @@ int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
 
        return 0;
 }
+
+int perf_hpp__alloc_mem_stats(struct perf_hpp_list *list, struct evlist *evlist)
+{
+       struct perf_hpp_fmt *fmt;
+       struct evsel *evsel;
+       enum mem_stat_type mst[16];
+       unsigned nr_mem_stats = 0;
+
+       perf_hpp_list__for_each_format(list, fmt) {
+               if (!perf_hpp__is_mem_stat_entry(fmt))
+                       continue;
+
+               assert(nr_mem_stats < ARRAY_SIZE(mst));
+               mst[nr_mem_stats++] = PERF_MEM_STAT_UNKNOWN;
+       }
+
+       if (nr_mem_stats == 0)
+               return 0;
+
+       evlist__for_each_entry(evlist, evsel) {
+               struct hists *hists = evsel__hists(evsel);
+
+               hists->mem_stat_types = calloc(nr_mem_stats,
+                                              sizeof(*hists->mem_stat_types));
+               if (hists->mem_stat_types == NULL)
+                       return -ENOMEM;
+
+               memcpy(hists->mem_stat_types, mst, nr_mem_stats * sizeof(*mst));
+               hists->nr_mem_stats = nr_mem_stats;
+       }
+       return 0;
+}
index fcb9f0db0c92a229db315473fc597bc9efd8ce37..7759c1818c1ad168ae07176d230d2db8d93c0e1f 100644 (file)
@@ -349,9 +349,10 @@ static int hists__update_mem_stat(struct hists *hists, struct hist_entry *he,
        }
 
        for (int i = 0; i < hists->nr_mem_stats; i++) {
-               int idx = 0; /* TODO: get correct index from mem info */
+               int idx = mem_stat_index(hists->mem_stat_types[i],
+                                        mem_info__const_data_src(mi)->val);
 
-               (void)mi;
+               assert(0 <= idx && idx < MEM_STAT_LEN);
                he->mem_stat[i].entries[idx] += period;
        }
        return 0;
@@ -3052,6 +3053,7 @@ static void hists_evsel__exit(struct evsel *evsel)
        struct perf_hpp_list_node *node, *tmp;
 
        hists__delete_all_entries(hists);
+       zfree(&hists->mem_stat_types);
 
        list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
                perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
index aba1d84ca074f27b83aeeb4de5f2d71f7386f91c..509af09691b84e1046e6b855ee75b067a9e4df88 100644 (file)
@@ -9,6 +9,7 @@
 #include "events_stats.h"
 #include "evsel.h"
 #include "map_symbol.h"
+#include "mem-events.h"
 #include "mutex.h"
 #include "sample.h"
 #include "spark.h"
@@ -133,6 +134,7 @@ struct hists {
        struct list_head        hpp_formats;
        int                     nr_hpp_node;
        int                     nr_mem_stats;
+       enum mem_stat_type      *mem_stat_types;
 };
 
 #define hists__has(__h, __f) (__h)->hpp_list->__f
@@ -597,6 +599,8 @@ void perf_hpp__reset_output_field(struct perf_hpp_list *list);
 void perf_hpp__append_sort_keys(struct perf_hpp_list *list);
 int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
                                  struct evlist *evlist);
+int perf_hpp__alloc_mem_stats(struct perf_hpp_list *list,
+                             struct evlist *evlist);
 
 
 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
index 884d9aebce9199c0f55c3211d163ffc139c54be4..1bc60ad3dc3125429c148d7ef1b9256658864724 100644 (file)
@@ -799,3 +799,21 @@ void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
        stats->nomap            += add->nomap;
        stats->noparse          += add->noparse;
 }
+
+/*
+ * It returns an index in hist_entry->mem_stat array for the given val which
+ * represents a data-src based on the mem_stat_type.
+ *
+ * For example, when mst is about cache level, the index can be 1 for L1, 2 for
+ * L2 and so on.
+ */
+int mem_stat_index(const enum mem_stat_type mst, const u64 val)
+{
+       switch (mst) {
+       case PERF_MEM_STAT_UNKNOWN:  /* placeholder */
+       default:
+               break;
+       }
+       (void)val;
+       return -1;
+}
index a5c19d39ee37147b52d8f0788690b26b38684759..2604464f985815f683b2c18bac41d54144ceb7f0 100644 (file)
@@ -89,4 +89,10 @@ struct hist_entry;
 int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi);
 void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add);
 
+enum mem_stat_type {
+       PERF_MEM_STAT_UNKNOWN,  /* placeholder */
+};
+
+int mem_stat_index(const enum mem_stat_type mst, const u64 data_src);
+
 #endif /* __PERF_MEM_EVENTS_H */
index ae8b8ceb82f3d00b46bb53614e638854ecf50f8f..6024f588f66f3156bd3ed51764d57abfa6f6f8db 100644 (file)
@@ -4163,6 +4163,10 @@ int setup_sorting(struct evlist *evlist)
        if (err < 0)
                return err;
 
+       err = perf_hpp__alloc_mem_stats(&perf_hpp_list, evlist);
+       if (err < 0)
+               return err;
+
        /* copy sort keys to output fields */
        perf_hpp__setup_output_field(&perf_hpp_list);
        /* and then copy output fields to sort keys */