[PATCH 4/9] perf tools: Maintain cgroup hierarchy

From: Namhyung Kim
Date: Wed Aug 28 2019 - 03:32:01 EST


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 <namhyung@xxxxxxxxxx>
---
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