Each cgroup is kept in the global cgroup_tree sorted by the inode
number.  Hist entries have cgroup ino number can compare it directly
and later it can be used to find a group name using this tree.

Signed-off-by: Namhyung Kim <namhy...@kernel.org>
---
 tools/perf/util/cgroup.c  | 72 +++++++++++++++++++++++++++++++++++++++
 tools/perf/util/cgroup.h  | 15 +++++---
 tools/perf/util/machine.c |  7 ++++
 tools/perf/util/session.c |  4 +++
 4 files changed, 94 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index f73599f271ff..8e4c26ea5078 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -12,6 +12,8 @@
 
 int nr_cgroups;
 
+static struct rb_root cgroup_tree = RB_ROOT;
+
 static int
 cgroupfs_find_mountpoint(char *buf, size_t maxlen)
 {
@@ -249,3 +251,73 @@ int parse_cgroups(const struct option *opt, const char 
*str,
        }
        return 0;
 }
+
+struct cgroup *cgroup__findnew(uint64_t ino, const char *path)
+{
+       struct rb_node **p = &cgroup_tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct cgroup *cgrp;
+
+       while (*p != NULL) {
+               parent = *p;
+               cgrp = rb_entry(parent, struct cgroup, node);
+
+               if (cgrp->ino == ino)
+                       return cgrp;
+
+               if (cgrp->ino < ino)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+
+       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->ino = ino;
+       refcount_set(&cgrp->refcnt, 1);
+
+       rb_link_node(&cgrp->node, parent, p);
+       rb_insert_color(&cgrp->node, &cgroup_tree);
+
+       return cgrp;
+}
+
+struct cgroup *cgroup__find_by_path(const char *path)
+{
+       struct rb_node *node;
+
+       node = rb_first(&cgroup_tree);
+       while (node) {
+               struct cgroup *cgrp = rb_entry(node, struct cgroup, node);
+
+               if (!strcmp(cgrp->name, path))
+                       return cgrp;
+
+               node = rb_next(&cgrp->node);
+       }
+
+       return NULL;
+}
+
+void destroy_cgroups(void)
+{
+       struct rb_node *node;
+       struct cgroup *cgrp;
+
+       while (!RB_EMPTY_ROOT(&cgroup_tree)) {
+               node = rb_first(&cgroup_tree);
+               cgrp = rb_entry(node, struct cgroup, node);
+
+               rb_erase(node, &cgroup_tree);
+               cgroup__put(cgrp);
+       }
+}
diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h
index 2ec11f01090d..11a8b187ec09 100644
--- a/tools/perf/util/cgroup.h
+++ b/tools/perf/util/cgroup.h
@@ -3,16 +3,18 @@
 #define __CGROUP_H__
 
 #include <linux/refcount.h>
+#include <linux/rbtree.h>
 
 struct option;
 
 struct cgroup {
-       char *name;
-       int fd;
-       refcount_t refcnt;
+       struct rb_node          node;
+       u64                     ino;
+       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 +28,9 @@ 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(uint64_t ino, const char *path);
+struct cgroup *cgroup__find_by_path(const char *path);
+
+void destroy_cgroups(void);
+
 #endif /* __CGROUP_H__ */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 61c35eef616b..33554e745e6b 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -26,6 +26,7 @@
 #include "linux/hash.h"
 #include "asm/bug.h"
 #include "bpf-event.h"
+#include "cgroup.h"
 
 #include <linux/ctype.h>
 #include <symbol/kallsyms.h>
@@ -646,9 +647,15 @@ int machine__process_cgroup_event(struct machine *machine 
__maybe_unused,
                                  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(event->cgroup.ino, event->cgroup.path);
+       if (cgrp == NULL)
+               return -ENOMEM;
+
        return 0;
 }
 
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 2cdce7ee228c..ffdd956d0a89 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -275,6 +275,8 @@ static void perf_session__release_decomp_events(struct 
perf_session *session)
        } while (1);
 }
 
+extern void destroy_cgroups(void);
+
 void perf_session__delete(struct perf_session *session)
 {
        if (session == NULL)
@@ -289,6 +291,8 @@ void perf_session__delete(struct perf_session *session)
        if (session->data)
                perf_data__close(session->data);
        free(session);
+
+       destroy_cgroups();
 }
 
 static int process_event_synth_tracing_data_stub(struct perf_session *session
-- 
2.23.0.187.g17f5b7556c-goog

Reply via email to