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)
111 zfree(&cgroup->name);
115 void cgroup__put(struct cgroup *cgrp)
117 if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
118 cgroup__delete(cgrp);
122 struct cgroup *cgroup__get(struct cgroup *cgroup)
125 refcount_inc(&cgroup->refcnt);
129 static void evsel__set_default_cgroup(struct evsel *evsel, struct cgroup *cgroup)
131 if (evsel->cgrp == NULL)
132 evsel->cgrp = cgroup__get(cgroup);
135 void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup)
139 evlist__for_each_entry(evlist, evsel)
140 evsel__set_default_cgroup(evsel, cgroup);
143 int parse_cgroups(const struct option *opt, const char *str,
144 int unset __maybe_unused)
146 struct evlist *evlist = *(struct evlist **)opt->value;
147 struct evsel *counter;
148 struct cgroup *cgrp = NULL;
149 const char *p, *e, *eos = str + strlen(str);
153 if (list_empty(&evlist->core.entries)) {
154 fprintf(stderr, "must define events before cgroups\n");
159 p = strchr(str, ',');
162 /* allow empty cgroups, i.e., skip */
164 /* termination added */
165 s = strndup(str, e - str);
168 ret = add_cgroup(evlist, s);
173 /* nr_cgroups is increased een for empty cgroups */
179 /* for the case one cgroup combine to multiple events */
181 if (nr_cgroups == 1) {
182 evlist__for_each_entry(evlist, counter) {
184 cgrp = counter->cgrp;
186 counter->cgrp = cgrp;
187 refcount_inc(&cgrp->refcnt);
195 static struct cgroup *__cgroup__findnew(struct rb_root *root, uint64_t id,
196 bool create, const char *path)
198 struct rb_node **p = &root->rb_node;
199 struct rb_node *parent = NULL;
204 cgrp = rb_entry(parent, struct cgroup, node);
218 cgrp = malloc(sizeof(*cgrp));
222 cgrp->name = strdup(path);
223 if (cgrp->name == NULL) {
230 refcount_set(&cgrp->refcnt, 1);
232 rb_link_node(&cgrp->node, parent, p);
233 rb_insert_color(&cgrp->node, root);
238 struct cgroup *cgroup__findnew(struct perf_env *env, uint64_t id,
243 down_write(&env->cgroups.lock);
244 cgrp = __cgroup__findnew(&env->cgroups.tree, id, true, path);
245 up_write(&env->cgroups.lock);
249 struct cgroup *cgroup__find(struct perf_env *env, uint64_t id)
253 down_read(&env->cgroups.lock);
254 cgrp = __cgroup__findnew(&env->cgroups.tree, id, false, NULL);
255 up_read(&env->cgroups.lock);
259 void perf_env__purge_cgroups(struct perf_env *env)
261 struct rb_node *node;
264 down_write(&env->cgroups.lock);
265 while (!RB_EMPTY_ROOT(&env->cgroups.tree)) {
266 node = rb_first(&env->cgroups.tree);
267 cgrp = rb_entry(node, struct cgroup, node);
269 rb_erase(node, &env->cgroups.tree);
272 up_write(&env->cgroups.lock);