]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf hist: Hide unused mem stat columns
authorNamhyung Kim <namhyung@kernel.org>
Wed, 30 Apr 2025 20:55:45 +0000 (13:55 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 2 May 2025 18:36:14 +0000 (15:36 -0300)
Some mem_stat types don't use all 8 columns.  And there are cases only
samples in certain kinds of mem_stat types are available only.  For that
case hide columns which has no samples.

The new output for the previous data would be:

  $ perf mem report -F overhead,op,comm --stdio
  ...
  #           ------ Mem Op -------
  # Overhead     Load  Store  Other  Command
  # ........  .....................  ...............
  #
      44.85%    21.1%  30.7%  48.3%  swapper
      26.82%    98.8%   0.3%   0.9%  netsli-prober
       7.19%    51.7%  13.7%  34.6%  perf
       5.81%    89.7%   2.2%   8.1%  qemu-system-ppc
       4.77%   100.0%   0.0%   0.0%  notifications_c
       1.77%    95.9%   1.2%   3.0%  MemoryReleaser
       0.77%    71.6%   4.1%  24.3%  DefaultEventMan
       0.19%    66.7%  22.2%  11.1%  gnome-shell
       ...

On Intel machines, the event is only for loads or stores so it'll have
only one column:

  #            Mem Op
  # Overhead     Load  Command
  # ........  .......  ...............
  #
      20.55%   100.0%  swapper
      17.13%   100.0%  chrome
       9.02%   100.0%  data-loop.0
       6.26%   100.0%  pipewire-pulse
       5.63%   100.0%  threaded-ml
       5.47%   100.0%  GraphRunner
       5.37%   100.0%  AudioIP~allback
       5.30%   100.0%  Chrome_ChildIOT
       3.17%   100.0%  Isolated Web Co
       ...

Committer testing:

  # grep "model name" -m1 /proc/cpuinfo
  model name : AMD Ryzen 9 9950X3D 16-Core Processo
  # perf mem report -F overhead,op,comm --stdio
  # Total Lost Samples: 0
  #
  # Samples: 2K of event 'cycles:P'
  # Total weight : 2637
  # Sort order   : local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked,blocked,local_ins_lat,local_p_stage_cyc
  #
  #           ------ Mem Op -------
  # Overhead     Load  Store  Other  Command
  # ........  .....................  ...............
  #
      61.02%    14.4%  25.5%  60.1%  swapper
       5.61%    26.4%  13.5%  60.1%  Isolated Web Co
       5.50%    21.4%  29.7%  49.0%  perf
       4.74%    27.2%  15.2%  57.6%  gnome-shell
       4.63%    33.6%  11.5%  54.9%  mdns_service
       4.29%    28.3%  12.4%  59.3%  ptyxis
       2.16%    24.6%  19.3%  56.1%  DOM Worker
       0.99%    23.1%  34.6%  42.3%  firefox
       0.72%    26.3%  15.8%  57.9%  IPC I/O Parent
       0.61%    12.5%  12.5%  75.0%  kworker/u130:20
       0.61%    37.5%  18.8%  43.8%  podman
       0.57%    33.3%   6.7%  60.0%  Timer
       0.53%    14.3%   7.1%  78.6%  KMS thread
       0.49%    30.8%   7.7%  61.5%  kworker/u130:3-
       0.46%    41.7%  33.3%  25.0%  IPDL Background

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: 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-9-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

index 427ce687ad815a62d7837a20663a559e59d033cc..661922c4d786322442812448290fbc1f16e516f3 100644 (file)
@@ -178,6 +178,9 @@ int hpp__fmt_mem_stat(struct perf_hpp_fmt *fmt __maybe_unused, struct perf_hpp *
        for (int i = 0; i < MEM_STAT_LEN; i++) {
                u64 val = he->mem_stat[mem_stat_idx].entries[i];
 
+               if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0)
+                       continue;
+
                ret += hpp__call_print_fn(hpp, print_fn, fmtstr, 100.0 * val / total);
        }
 
@@ -405,12 +408,31 @@ static int hpp__header_mem_stat_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hp
        int ret = 0;
        int len;
        enum mem_stat_type mst = hpp__mem_stat_type(fmt);
+       int mem_stat_idx = -1;
+
+       for (int i = 0; i < hists->nr_mem_stats; i++) {
+               if (hists->mem_stat_types[i] == mst) {
+                       mem_stat_idx = i;
+                       break;
+               }
+       }
+       assert(mem_stat_idx != -1);
 
-       (void)hists;
        if (line == 0) {
                int left, right;
 
-               len = fmt->len;
+               len = 0;
+               /* update fmt->len for acutally used columns only */
+               for (int i = 0; i < MEM_STAT_LEN; i++) {
+                       if (hists->mem_stat_total[mem_stat_idx].entries[i])
+                               len += MEM_STAT_PRINT_LEN;
+               }
+               fmt->len = len;
+
+               /* print header directly if single column only */
+               if (len == MEM_STAT_PRINT_LEN)
+                       return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
+
                left = (len - strlen(fmt->name)) / 2 - 1;
                right = len - left - strlen(fmt->name) - 2;
 
@@ -423,10 +445,14 @@ static int hpp__header_mem_stat_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hp
                                 left, graph_dotted_line, fmt->name, right, graph_dotted_line);
        }
 
+
        len = hpp->size;
        for (int i = 0; i < MEM_STAT_LEN; i++) {
                int printed;
 
+               if (hists->mem_stat_total[mem_stat_idx].entries[i] == 0)
+                       continue;
+
                printed = scnprintf(buf, len, "%*s", MEM_STAT_PRINT_LEN,
                                    mem_stat_name(mst, i));
                ret += printed;
@@ -1214,6 +1240,11 @@ int perf_hpp__alloc_mem_stats(struct perf_hpp_list *list, struct evlist *evlist)
                if (hists->mem_stat_types == NULL)
                        return -ENOMEM;
 
+               hists->mem_stat_total = calloc(nr_mem_stats,
+                                              sizeof(*hists->mem_stat_total));
+               if (hists->mem_stat_total == NULL)
+                       return -ENOMEM;
+
                memcpy(hists->mem_stat_types, mst, nr_mem_stats * sizeof(*mst));
                hists->nr_mem_stats = nr_mem_stats;
        }
index 7759c1818c1ad168ae07176d230d2db8d93c0e1f..afc6855327ab0de66d0642854328a3929b137fb2 100644 (file)
@@ -354,6 +354,7 @@ static int hists__update_mem_stat(struct hists *hists, struct hist_entry *he,
 
                assert(0 <= idx && idx < MEM_STAT_LEN);
                he->mem_stat[i].entries[idx] += period;
+               hists->mem_stat_total[i].entries[idx] += period;
        }
        return 0;
 }
@@ -3054,6 +3055,7 @@ static void hists_evsel__exit(struct evsel *evsel)
 
        hists__delete_all_entries(hists);
        zfree(&hists->mem_stat_types);
+       zfree(&hists->mem_stat_total);
 
        list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
                perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
index 3990cfc21b1615ae8affabef40f0e5b65876aa31..fa5e886e5b04ec9b46fa1e4704648ea42af7719f 100644 (file)
@@ -135,6 +135,7 @@ struct hists {
        int                     nr_hpp_node;
        int                     nr_mem_stats;
        enum mem_stat_type      *mem_stat_types;
+       struct he_mem_stat      *mem_stat_total;
 };
 
 #define hists__has(__h, __f) (__h)->hpp_list->__f