perf report: Add 'cgroup' sort key
authorNamhyung Kim <namhyung@kernel.org>
Wed, 25 Mar 2020 12:45:32 +0000 (21:45 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 3 Apr 2020 12:37:55 +0000 (09:37 -0300)
The cgroup sort key is to show cgroup membership of each task.
Currently it shows full path in the cgroupfs (not relative to the root
of cgroup namespace) since it'd be more intuitive IMHO.  Otherwise root
cgroup in different namespaces will all show same name - "/".

The cgroup sort key should come before cgroup_id otherwise
sort_dimension__add() will match it to cgroup_id as it only matches with
the given substring.

For example it will look like following.  Note that record patch adding
--all-cgroups patch will come later.

  $ perf record -a --namespace --all-cgroups  cgtest
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.208 MB perf.data (4090 samples) ]

  $ perf report -s cgroup_id,cgroup,pid
  ...
  # Overhead  cgroup id (dev/inode)  Cgroup          Pid:Command
  # ........  .....................  ..........  ...............
  #
      93.96%  0/0x0                  /                 0:swapper
       1.25%  3/0xeffffffb           /               278:looper0
       0.86%  3/0xf000015f           /sub/cgrp1      280:cgtest
       0.37%  3/0xf0000160           /sub/cgrp2      281:cgtest
       0.34%  3/0xf0000163           /sub/cgrp3      282:cgtest
       0.22%  3/0xeffffffb           /sub            278:looper0
       0.20%  3/0xeffffffb           /               280:cgtest
       0.15%  3/0xf0000163           /sub/cgrp3      285:looper3

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lore.kernel.org/lkml/20200325124536.2800725-6-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-report.txt
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/sort.c
tools/perf/util/sort.h

index e56e3f1344a70e286823120534d652925860531a..f569b9ea40027b96448f268fd9cdbc865109fa65 100644 (file)
@@ -95,6 +95,7 @@ OPTIONS
        abort cost. This is the global weight.
        - local_weight: Local weight version of the weight above.
        - cgroup_id: ID derived from cgroup namespace device and inode numbers.
+       - cgroup: cgroup pathname in the cgroupfs.
        - transaction: Transaction abort flags.
        - overhead: Overhead percentage of sample
        - overhead_sys: Overhead percentage of sample running in system mode
index e74a5acf66d948ebd424857686c081a43da5ae58..283a69ff6a3dcf941506cbbd7f4a5ed9e7ec7dd0 100644 (file)
@@ -10,6 +10,7 @@
 #include "mem-events.h"
 #include "session.h"
 #include "namespaces.h"
+#include "cgroup.h"
 #include "sort.h"
 #include "units.h"
 #include "evlist.h"
@@ -194,6 +195,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
                hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
        }
 
+       hists__new_col_len(hists, HISTC_CGROUP, 6);
        hists__new_col_len(hists, HISTC_CGROUP_ID, 20);
        hists__new_col_len(hists, HISTC_CPU, 3);
        hists__new_col_len(hists, HISTC_SOCKET, 6);
@@ -222,6 +224,16 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 
        if (h->trace_output)
                hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
+
+       if (h->cgroup) {
+               const char *cgrp_name = "unknown";
+               struct cgroup *cgrp = cgroup__find(h->ms.maps->machine->env,
+                                                  h->cgroup);
+               if (cgrp != NULL)
+                       cgrp_name = cgrp->name;
+
+               hists__new_col_len(hists, HISTC_CGROUP, strlen(cgrp_name));
+       }
 }
 
 void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -691,6 +703,7 @@ __hists__add_entry(struct hists *hists,
                        .dev = ns ? ns->link_info[CGROUP_NS_INDEX].dev : 0,
                        .ino = ns ? ns->link_info[CGROUP_NS_INDEX].ino : 0,
                },
+               .cgroup = sample->cgroup,
                .ms = {
                        .maps   = al->maps,
                        .map    = al->map,
index bb994e030495900d83c6d22d6061d60677713756..4141295a66fa3e35e633cdc0fbd5a297d6b4ae08 100644 (file)
@@ -38,6 +38,7 @@ enum hist_column {
        HISTC_THREAD,
        HISTC_COMM,
        HISTC_CGROUP_ID,
+       HISTC_CGROUP,
        HISTC_PARENT,
        HISTC_CPU,
        HISTC_SOCKET,
index e860595576c2406d488783796fa5f004f599be9b..f14cc728c358a84c016ac3951cc147571b19902e 100644 (file)
@@ -12,6 +12,7 @@
 #include "cacheline.h"
 #include "comm.h"
 #include "map.h"
+#include "maps.h"
 #include "symbol.h"
 #include "map_symbol.h"
 #include "branch.h"
@@ -25,6 +26,8 @@
 #include "mem-events.h"
 #include "annotate.h"
 #include "time-utils.h"
+#include "cgroup.h"
+#include "machine.h"
 #include <linux/kernel.h>
 #include <linux/string.h>
 
@@ -634,6 +637,39 @@ struct sort_entry sort_cgroup_id = {
        .se_width_idx   = HISTC_CGROUP_ID,
 };
 
+/* --sort cgroup */
+
+static int64_t
+sort__cgroup_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       return right->cgroup - left->cgroup;
+}
+
+static int hist_entry__cgroup_snprintf(struct hist_entry *he,
+                                      char *bf, size_t size,
+                                      unsigned int width __maybe_unused)
+{
+       const char *cgrp_name = "N/A";
+
+       if (he->cgroup) {
+               struct cgroup *cgrp = cgroup__find(he->ms.maps->machine->env,
+                                                  he->cgroup);
+               if (cgrp != NULL)
+                       cgrp_name = cgrp->name;
+               else
+                       cgrp_name = "unknown";
+       }
+
+       return repsep_snprintf(bf, size, "%s", cgrp_name);
+}
+
+struct sort_entry sort_cgroup = {
+       .se_header      = "Cgroup",
+       .se_cmp         = sort__cgroup_cmp,
+       .se_snprintf    = hist_entry__cgroup_snprintf,
+       .se_width_idx   = HISTC_CGROUP,
+};
+
 /* --sort socket */
 
 static int64_t
@@ -1660,6 +1696,7 @@ static struct sort_dimension common_sort_dimensions[] = {
        DIM(SORT_TRACE, "trace", sort_trace),
        DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
        DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size),
+       DIM(SORT_CGROUP, "cgroup", sort_cgroup),
        DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
        DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null),
        DIM(SORT_TIME, "time", sort_time),
index 6c862d62d05258c5105ef795c3b2d6089d4ddecf..cfa6ac6f7d06da5580542767ff04800ee61c8583 100644 (file)
@@ -101,6 +101,7 @@ struct hist_entry {
        struct thread           *thread;
        struct comm             *comm;
        struct namespace_id     cgroup_id;
+       u64                     cgroup;
        u64                     ip;
        u64                     transaction;
        s32                     socket;
@@ -224,6 +225,7 @@ enum sort_type {
        SORT_TRACE,
        SORT_SYM_SIZE,
        SORT_DSO_SIZE,
+       SORT_CGROUP,
        SORT_CGROUP_ID,
        SORT_SYM_IPC_NULL,
        SORT_TIME,