perf cgroup: Maintain cgroup hierarchy
authorNamhyung Kim <namhyung@kernel.org>
Wed, 25 Mar 2020 12:45:31 +0000 (21:45 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 3 Apr 2020 12:37:55 +0000 (09:37 -0300)
Each cgroup is kept in the perf_env's cgroup_tree sorted by the cgroup
id.  Hist entries have cgroup id can compare it directly and later it
can be used to find a group name using this tree.

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-5-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/cgroup.c
tools/perf/util/cgroup.h
tools/perf/util/env.c
tools/perf/util/env.h
tools/perf/util/machine.c

index 5bc9d3b01bd9200ab84349d27924598ae64f453b..b73fb78230486005f6017238b0682f074086065e 100644 (file)
@@ -191,3 +191,83 @@ int parse_cgroups(const struct option *opt, const char *str,
        }
        return 0;
 }
+
+static struct cgroup *__cgroup__findnew(struct rb_root *root, uint64_t id,
+                                       bool create, const char *path)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct cgroup *cgrp;
+
+       while (*p != NULL) {
+               parent = *p;
+               cgrp = rb_entry(parent, struct cgroup, node);
+
+               if (cgrp->id == id)
+                       return cgrp;
+
+               if (cgrp->id < id)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       if (!create)
+               return NULL;
+
+       cgrp = malloc(sizeof(*cgrp));
+       if (cgrp == NULL)
+               return NULL;
+
+       cgrp->name = strdup(path);
+       if (cgrp->name == NULL) {
+               free(cgrp);
+               return NULL;
+       }
+
+       cgrp->fd = -1;
+       cgrp->id = id;
+       refcount_set(&cgrp->refcnt, 1);
+
+       rb_link_node(&cgrp->node, parent, p);
+       rb_insert_color(&cgrp->node, root);
+
+       return cgrp;
+}
+
+struct cgroup *cgroup__findnew(struct perf_env *env, uint64_t id,
+                              const char *path)
+{
+       struct cgroup *cgrp;
+
+       down_write(&env->cgroups.lock);
+       cgrp = __cgroup__findnew(&env->cgroups.tree, id, true, path);
+       up_write(&env->cgroups.lock);
+       return cgrp;
+}
+
+struct cgroup *cgroup__find(struct perf_env *env, uint64_t id)
+{
+       struct cgroup *cgrp;
+
+       down_read(&env->cgroups.lock);
+       cgrp = __cgroup__findnew(&env->cgroups.tree, id, false, NULL);
+       up_read(&env->cgroups.lock);
+       return cgrp;
+}
+
+void perf_env__purge_cgroups(struct perf_env *env)
+{
+       struct rb_node *node;
+       struct cgroup *cgrp;
+
+       down_write(&env->cgroups.lock);
+       while (!RB_EMPTY_ROOT(&env->cgroups.tree)) {
+               node = rb_first(&env->cgroups.tree);
+               cgrp = rb_entry(node, struct cgroup, node);
+
+               rb_erase(node, &env->cgroups.tree);
+               cgroup__put(cgrp);
+       }
+       up_write(&env->cgroups.lock);
+}
index 2ec11f01090d6e38f3afafcb9005ae8d2d761b99..e98d5975fe550d944f82e4df272416fb6bedeaf7 100644 (file)
@@ -3,16 +3,19 @@
 #define __CGROUP_H__
 
 #include <linux/refcount.h>
+#include <linux/rbtree.h>
+#include "util/env.h"
 
 struct option;
 
 struct cgroup {
-       char *name;
-       int fd;
-       refcount_t refcnt;
+       struct rb_node          node;
+       u64                     id;
+       char                    *name;
+       int                     fd;
+       refcount_t              refcnt;
 };
 
-
 extern int nr_cgroups; /* number of explicit cgroups defined */
 
 struct cgroup *cgroup__get(struct cgroup *cgroup);
@@ -26,4 +29,10 @@ void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup);
 
 int parse_cgroups(const struct option *opt, const char *str, int unset);
 
+struct cgroup *cgroup__findnew(struct perf_env *env, uint64_t id,
+                              const char *path);
+struct cgroup *cgroup__find(struct perf_env *env, uint64_t id);
+
+void perf_env__purge_cgroups(struct perf_env *env);
+
 #endif /* __CGROUP_H__ */
index 4154f944f474a4152d4469c652a040db4b05a78a..fadc59708ece020220e07ab4ee98514688ef4718 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/ctype.h>
 #include <linux/zalloc.h>
 #include "bpf-event.h"
+#include "cgroup.h"
 #include <errno.h>
 #include <sys/utsname.h>
 #include <bpf/libbpf.h>
@@ -168,6 +169,7 @@ void perf_env__exit(struct perf_env *env)
        int i;
 
        perf_env__purge_bpf(env);
+       perf_env__purge_cgroups(env);
        zfree(&env->hostname);
        zfree(&env->os_release);
        zfree(&env->version);
index 11d05ae3606a012df2070b0a0b1307669efabea2..7632075a87922b264f0b54f14d961731300c65a7 100644 (file)
@@ -88,6 +88,12 @@ struct perf_env {
                u32                     btfs_cnt;
        } bpf_progs;
 
+       /* same reason as above (for perf-top) */
+       struct {
+               struct rw_semaphore     lock;
+               struct rb_root          tree;
+       } cgroups;
+
        /* For fast cpu to numa node lookup via perf_env__numa_node */
        int                     *numa_map;
        int                      nr_numa_map;
index 399b4731b24608c8e8e8130d22e93c58356f511d..97142e9671be3ed5b2d494a4194531b444510567 100644 (file)
@@ -33,6 +33,7 @@
 #include "asm/bug.h"
 #include "bpf-event.h"
 #include <internal/lib.h> // page_size
+#include "cgroup.h"
 
 #include <linux/ctype.h>
 #include <symbol/kallsyms.h>
@@ -654,13 +655,19 @@ int machine__process_namespaces_event(struct machine *machine __maybe_unused,
        return err;
 }
 
-int machine__process_cgroup_event(struct machine *machine __maybe_unused,
+int machine__process_cgroup_event(struct machine *machine,
                                  union perf_event *event,
                                  struct perf_sample *sample __maybe_unused)
 {
+       struct cgroup *cgrp;
+
        if (dump_trace)
                perf_event__fprintf_cgroup(event, stdout);
 
+       cgrp = cgroup__findnew(machine->env, event->cgroup.id, event->cgroup.path);
+       if (cgrp == NULL)
+               return -ENOMEM;
+
        return 0;
 }