1 // SPDX-License-Identifier: GPL-2.0
2 #include <subcmd/parse-options.h>
6 #include <linux/zalloc.h>
12 #include <api/fs/fs.h>
16 static int open_cgroup(const char *name)
18 char path[PATH_MAX + 1];
19 char mnt[PATH_MAX + 1];
23 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1, "perf_event"))
26 scnprintf(path, PATH_MAX, "%s/%s", mnt, name);
28 fd = open(path, O_RDONLY);
30 fprintf(stderr, "no access to cgroup %s\n", path);
35 static struct cgroup *evlist__find_cgroup(struct evlist *evlist, const char *str)
37 struct evsel *counter;
39 * check if cgrp is already defined, if so we reuse it
41 evlist__for_each_entry(evlist, counter) {
44 if (!strcmp(counter->cgrp->name, str))
45 return cgroup__get(counter->cgrp);
51 static struct cgroup *cgroup__new(const char *name)
53 struct cgroup *cgroup = zalloc(sizeof(*cgroup));
56 refcount_set(&cgroup->refcnt, 1);
58 cgroup->name = strdup(name);
61 cgroup->fd = open_cgroup(name);
75 struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name)
77 struct cgroup *cgroup = evlist__find_cgroup(evlist, name);
79 return cgroup ?: cgroup__new(name);
82 static int add_cgroup(struct evlist *evlist, const char *str)
84 struct evsel *counter;
85 struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str);
91 * find corresponding event
92 * if add cgroup N, then need to find event N
95 evlist__for_each_entry(evlist, counter) {
104 counter->cgrp = cgrp;
108 static void cgroup__delete(struct cgroup *cgroup)
112 zfree(&cgroup->name);
116 void cgroup__put(struct cgroup *cgrp)
118 if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
119 cgroup__delete(cgrp);
123 struct cgroup *cgroup__get(struct cgroup *cgroup)
126 refcount_inc(&cgroup->refcnt);
130 static void evsel__set_default_cgroup(struct evsel *evsel, struct cgroup *cgroup)
132 if (evsel->cgrp == NULL)
133 evsel->cgrp = cgroup__get(cgroup);
136 void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup)
140 evlist__for_each_entry(evlist, evsel)
141 evsel__set_default_cgroup(evsel, cgroup);
144 int parse_cgroups(const struct option *opt, const char *str,
145 int unset __maybe_unused)
147 struct evlist *evlist = *(struct evlist **)opt->value;
148 struct evsel *counter;
149 struct cgroup *cgrp = NULL;
150 const char *p, *e, *eos = str + strlen(str);
154 if (list_empty(&evlist->core.entries)) {
155 fprintf(stderr, "must define events before cgroups\n");
160 p = strchr(str, ',');
163 /* allow empty cgroups, i.e., skip */
165 /* termination added */
166 s = strndup(str, e - str);
169 ret = add_cgroup(evlist, s);
174 /* nr_cgroups is increased een for empty cgroups */
180 /* for the case one cgroup combine to multiple events */
182 if (nr_cgroups == 1) {
183 evlist__for_each_entry(evlist, counter) {
185 cgrp = counter->cgrp;
187 counter->cgrp = cgrp;
188 refcount_inc(&cgrp->refcnt);
196 static struct cgroup *__cgroup__findnew(struct rb_root *root, uint64_t id,
197 bool create, const char *path)
199 struct rb_node **p = &root->rb_node;
200 struct rb_node *parent = NULL;
205 cgrp = rb_entry(parent, struct cgroup, node);
219 cgrp = malloc(sizeof(*cgrp));
223 cgrp->name = strdup(path);
224 if (cgrp->name == NULL) {
231 refcount_set(&cgrp->refcnt, 1);
233 rb_link_node(&cgrp->node, parent, p);
234 rb_insert_color(&cgrp->node, root);
239 struct cgroup *cgroup__findnew(struct perf_env *env, uint64_t id,
244 down_write(&env->cgroups.lock);
245 cgrp = __cgroup__findnew(&env->cgroups.tree, id, true, path);
246 up_write(&env->cgroups.lock);
250 struct cgroup *cgroup__find(struct perf_env *env, uint64_t id)
254 down_read(&env->cgroups.lock);
255 cgrp = __cgroup__findnew(&env->cgroups.tree, id, false, NULL);
256 up_read(&env->cgroups.lock);
260 void perf_env__purge_cgroups(struct perf_env *env)
262 struct rb_node *node;
265 down_write(&env->cgroups.lock);
266 while (!RB_EMPTY_ROOT(&env->cgroups.tree)) {
267 node = rb_first(&env->cgroups.tree);
268 cgrp = rb_entry(node, struct cgroup, node);
270 rb_erase(node, &env->cgroups.tree);
273 up_write(&env->cgroups.lock);