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
);