gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / tools / perf / util / cgroup.c
blobb73fb78230486005f6017238b0682f074086065e
1 // SPDX-License-Identifier: GPL-2.0
2 #include <subcmd/parse-options.h>
3 #include "evsel.h"
4 #include "cgroup.h"
5 #include "evlist.h"
6 #include <linux/zalloc.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <api/fs/fs.h>
14 int nr_cgroups;
16 static int open_cgroup(const char *name)
18 char path[PATH_MAX + 1];
19 char mnt[PATH_MAX + 1];
20 int fd;
23 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1, "perf_event"))
24 return -1;
26 scnprintf(path, PATH_MAX, "%s/%s", mnt, name);
28 fd = open(path, O_RDONLY);
29 if (fd == -1)
30 fprintf(stderr, "no access to cgroup %s\n", path);
32 return fd;
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) {
42 if (!counter->cgrp)
43 continue;
44 if (!strcmp(counter->cgrp->name, str))
45 return cgroup__get(counter->cgrp);
48 return NULL;
51 static struct cgroup *cgroup__new(const char *name)
53 struct cgroup *cgroup = zalloc(sizeof(*cgroup));
55 if (cgroup != NULL) {
56 refcount_set(&cgroup->refcnt, 1);
58 cgroup->name = strdup(name);
59 if (!cgroup->name)
60 goto out_err;
61 cgroup->fd = open_cgroup(name);
62 if (cgroup->fd == -1)
63 goto out_free_name;
66 return cgroup;
68 out_free_name:
69 zfree(&cgroup->name);
70 out_err:
71 free(cgroup);
72 return NULL;
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);
86 int n;
88 if (!cgrp)
89 return -1;
91 * find corresponding event
92 * if add cgroup N, then need to find event N
94 n = 0;
95 evlist__for_each_entry(evlist, counter) {
96 if (n == nr_cgroups)
97 goto found;
98 n++;
101 cgroup__put(cgrp);
102 return -1;
103 found:
104 counter->cgrp = cgrp;
105 return 0;
108 static void cgroup__delete(struct cgroup *cgroup)
110 close(cgroup->fd);
111 zfree(&cgroup->name);
112 free(cgroup);
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)
124 if (cgroup)
125 refcount_inc(&cgroup->refcnt);
126 return cgroup;
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)
137 struct evsel *evsel;
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);
150 char *s;
151 int ret, i;
153 if (list_empty(&evlist->core.entries)) {
154 fprintf(stderr, "must define events before cgroups\n");
155 return -1;
158 for (;;) {
159 p = strchr(str, ',');
160 e = p ? p : eos;
162 /* allow empty cgroups, i.e., skip */
163 if (e - str) {
164 /* termination added */
165 s = strndup(str, e - str);
166 if (!s)
167 return -1;
168 ret = add_cgroup(evlist, s);
169 free(s);
170 if (ret)
171 return -1;
173 /* nr_cgroups is increased een for empty cgroups */
174 nr_cgroups++;
175 if (!p)
176 break;
177 str = p+1;
179 /* for the case one cgroup combine to multiple events */
180 i = 0;
181 if (nr_cgroups == 1) {
182 evlist__for_each_entry(evlist, counter) {
183 if (i == 0)
184 cgrp = counter->cgrp;
185 else {
186 counter->cgrp = cgrp;
187 refcount_inc(&cgrp->refcnt);
189 i++;
192 return 0;
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;
200 struct cgroup *cgrp;
202 while (*p != NULL) {
203 parent = *p;
204 cgrp = rb_entry(parent, struct cgroup, node);
206 if (cgrp->id == id)
207 return cgrp;
209 if (cgrp->id < id)
210 p = &(*p)->rb_left;
211 else
212 p = &(*p)->rb_right;
215 if (!create)
216 return NULL;
218 cgrp = malloc(sizeof(*cgrp));
219 if (cgrp == NULL)
220 return NULL;
222 cgrp->name = strdup(path);
223 if (cgrp->name == NULL) {
224 free(cgrp);
225 return NULL;
228 cgrp->fd = -1;
229 cgrp->id = id;
230 refcount_set(&cgrp->refcnt, 1);
232 rb_link_node(&cgrp->node, parent, p);
233 rb_insert_color(&cgrp->node, root);
235 return cgrp;
238 struct cgroup *cgroup__findnew(struct perf_env *env, uint64_t id,
239 const char *path)
241 struct cgroup *cgrp;
243 down_write(&env->cgroups.lock);
244 cgrp = __cgroup__findnew(&env->cgroups.tree, id, true, path);
245 up_write(&env->cgroups.lock);
246 return cgrp;
249 struct cgroup *cgroup__find(struct perf_env *env, uint64_t id)
251 struct cgroup *cgrp;
253 down_read(&env->cgroups.lock);
254 cgrp = __cgroup__findnew(&env->cgroups.tree, id, false, NULL);
255 up_read(&env->cgroups.lock);
256 return cgrp;
259 void perf_env__purge_cgroups(struct perf_env *env)
261 struct rb_node *node;
262 struct cgroup *cgrp;
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);
270 cgroup__put(cgrp);
272 up_write(&env->cgroups.lock);