3 #include <subcmd/parse-options.h>
7 #include <linux/stringify.h>
12 cgroupfs_find_mountpoint(char *buf, size_t maxlen)
15 char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
16 char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
17 char *token, *saved_ptr = NULL;
19 fp = fopen("/proc/mounts", "r");
24 * in order to handle split hierarchy, we need to scan /proc/mounts
25 * and inspect every cgroupfs mount point to find one that has
26 * perf_event subsystem
31 while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
32 __stringify(PATH_MAX)"s %*d %*d\n",
33 mountpoint, type, tokens) == 3) {
35 if (!path_v1[0] && !strcmp(type, "cgroup")) {
37 token = strtok_r(tokens, ",", &saved_ptr);
39 while (token != NULL) {
40 if (!strcmp(token, "perf_event")) {
41 strcpy(path_v1, mountpoint);
44 token = strtok_r(NULL, ",", &saved_ptr);
48 if (!path_v2[0] && !strcmp(type, "cgroup2"))
49 strcpy(path_v2, mountpoint);
51 if (path_v1[0] && path_v2[0])
63 if (strlen(path) < maxlen) {
70 static int open_cgroup(char *name)
72 char path[PATH_MAX + 1];
73 char mnt[PATH_MAX + 1];
77 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
80 snprintf(path, PATH_MAX, "%s/%s", mnt, name);
82 fd = open(path, O_RDONLY);
84 fprintf(stderr, "no access to cgroup %s\n", path);
89 static int add_cgroup(struct perf_evlist *evlist, char *str)
91 struct perf_evsel *counter;
92 struct cgroup_sel *cgrp = NULL;
95 * check if cgrp is already defined, if so we reuse it
97 evlist__for_each_entry(evlist, counter) {
101 if (!strcmp(cgrp->name, str)) {
102 refcount_inc(&cgrp->refcnt);
110 cgrp = zalloc(sizeof(*cgrp));
115 refcount_set(&cgrp->refcnt, 1);
117 cgrp->fd = open_cgroup(str);
118 if (cgrp->fd == -1) {
125 * find corresponding event
126 * if add cgroup N, then need to find event N
129 evlist__for_each_entry(evlist, counter) {
134 if (refcount_dec_and_test(&cgrp->refcnt))
139 counter->cgrp = cgrp;
143 void close_cgroup(struct cgroup_sel *cgrp)
145 if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
152 int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
153 int unset __maybe_unused)
155 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
156 const char *p, *e, *eos = str + strlen(str);
160 if (list_empty(&evlist->entries)) {
161 fprintf(stderr, "must define events before cgroups\n");
166 p = strchr(str, ',');
169 /* allow empty cgroups, i.e., skip */
171 /* termination added */
172 s = strndup(str, e - str);
175 ret = add_cgroup(evlist, s);
181 /* nr_cgroups is increased een for empty cgroups */