hc
2024-05-10 23fa18eaa71266feff7ba8d83022d9e1cc83c65a
kernel/tools/perf/util/cgroup.c
....@@ -1,75 +1,20 @@
11 // SPDX-License-Identifier: GPL-2.0
2
-#include "util.h"
3
-#include "../perf.h"
42 #include <subcmd/parse-options.h>
53 #include "evsel.h"
64 #include "cgroup.h"
75 #include "evlist.h"
8
-#include <linux/stringify.h>
6
+#include "rblist.h"
7
+#include "metricgroup.h"
8
+#include "stat.h"
9
+#include <linux/zalloc.h>
910 #include <sys/types.h>
1011 #include <sys/stat.h>
1112 #include <fcntl.h>
13
+#include <stdlib.h>
14
+#include <string.h>
15
+#include <api/fs/fs.h>
1216
1317 int nr_cgroups;
14
-
15
-static int
16
-cgroupfs_find_mountpoint(char *buf, size_t maxlen)
17
-{
18
- FILE *fp;
19
- char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
20
- char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
21
- char *token, *saved_ptr = NULL;
22
-
23
- fp = fopen("/proc/mounts", "r");
24
- if (!fp)
25
- return -1;
26
-
27
- /*
28
- * in order to handle split hierarchy, we need to scan /proc/mounts
29
- * and inspect every cgroupfs mount point to find one that has
30
- * perf_event subsystem
31
- */
32
- path_v1[0] = '\0';
33
- path_v2[0] = '\0';
34
-
35
- while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
36
- __stringify(PATH_MAX)"s %*d %*d\n",
37
- mountpoint, type, tokens) == 3) {
38
-
39
- if (!path_v1[0] && !strcmp(type, "cgroup")) {
40
-
41
- token = strtok_r(tokens, ",", &saved_ptr);
42
-
43
- while (token != NULL) {
44
- if (!strcmp(token, "perf_event")) {
45
- strcpy(path_v1, mountpoint);
46
- break;
47
- }
48
- token = strtok_r(NULL, ",", &saved_ptr);
49
- }
50
- }
51
-
52
- if (!path_v2[0] && !strcmp(type, "cgroup2"))
53
- strcpy(path_v2, mountpoint);
54
-
55
- if (path_v1[0] && path_v2[0])
56
- break;
57
- }
58
- fclose(fp);
59
-
60
- if (path_v1[0])
61
- path = path_v1;
62
- else if (path_v2[0])
63
- path = path_v2;
64
- else
65
- return -1;
66
-
67
- if (strlen(path) < maxlen) {
68
- strcpy(buf, path);
69
- return 0;
70
- }
71
- return -1;
72
-}
7318
7419 static int open_cgroup(const char *name)
7520 {
....@@ -78,7 +23,7 @@
7823 int fd;
7924
8025
81
- if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
26
+ if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1, "perf_event"))
8227 return -1;
8328
8429 scnprintf(path, PATH_MAX, "%s/%s", mnt, name);
....@@ -90,9 +35,9 @@
9035 return fd;
9136 }
9237
93
-static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str)
38
+static struct cgroup *evlist__find_cgroup(struct evlist *evlist, const char *str)
9439 {
95
- struct perf_evsel *counter;
40
+ struct evsel *counter;
9641 /*
9742 * check if cgrp is already defined, if so we reuse it
9843 */
....@@ -106,7 +51,7 @@
10651 return NULL;
10752 }
10853
109
-static struct cgroup *cgroup__new(const char *name)
54
+static struct cgroup *cgroup__new(const char *name, bool do_open)
11055 {
11156 struct cgroup *cgroup = zalloc(sizeof(*cgroup));
11257
....@@ -116,30 +61,35 @@
11661 cgroup->name = strdup(name);
11762 if (!cgroup->name)
11863 goto out_err;
119
- cgroup->fd = open_cgroup(name);
120
- if (cgroup->fd == -1)
121
- goto out_free_name;
64
+
65
+ if (do_open) {
66
+ cgroup->fd = open_cgroup(name);
67
+ if (cgroup->fd == -1)
68
+ goto out_free_name;
69
+ } else {
70
+ cgroup->fd = -1;
71
+ }
12272 }
12373
12474 return cgroup;
12575
12676 out_free_name:
127
- free(cgroup->name);
77
+ zfree(&cgroup->name);
12878 out_err:
12979 free(cgroup);
13080 return NULL;
13181 }
13282
133
-struct cgroup *evlist__findnew_cgroup(struct perf_evlist *evlist, const char *name)
83
+struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name)
13484 {
13585 struct cgroup *cgroup = evlist__find_cgroup(evlist, name);
13686
137
- return cgroup ?: cgroup__new(name);
87
+ return cgroup ?: cgroup__new(name, true);
13888 }
13989
140
-static int add_cgroup(struct perf_evlist *evlist, const char *str)
90
+static int add_cgroup(struct evlist *evlist, const char *str)
14191 {
142
- struct perf_evsel *counter;
92
+ struct evsel *counter;
14393 struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str);
14494 int n;
14595
....@@ -165,7 +115,8 @@
165115
166116 static void cgroup__delete(struct cgroup *cgroup)
167117 {
168
- close(cgroup->fd);
118
+ if (cgroup->fd >= 0)
119
+ close(cgroup->fd);
169120 zfree(&cgroup->name);
170121 free(cgroup);
171122 }
....@@ -184,15 +135,15 @@
184135 return cgroup;
185136 }
186137
187
-static void evsel__set_default_cgroup(struct perf_evsel *evsel, struct cgroup *cgroup)
138
+static void evsel__set_default_cgroup(struct evsel *evsel, struct cgroup *cgroup)
188139 {
189140 if (evsel->cgrp == NULL)
190141 evsel->cgrp = cgroup__get(cgroup);
191142 }
192143
193
-void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgroup)
144
+void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup)
194145 {
195
- struct perf_evsel *evsel;
146
+ struct evsel *evsel;
196147
197148 evlist__for_each_entry(evlist, evsel)
198149 evsel__set_default_cgroup(evsel, cgroup);
....@@ -201,14 +152,14 @@
201152 int parse_cgroups(const struct option *opt, const char *str,
202153 int unset __maybe_unused)
203154 {
204
- struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
205
- struct perf_evsel *counter;
155
+ struct evlist *evlist = *(struct evlist **)opt->value;
156
+ struct evsel *counter;
206157 struct cgroup *cgrp = NULL;
207158 const char *p, *e, *eos = str + strlen(str);
208159 char *s;
209160 int ret, i;
210161
211
- if (list_empty(&evlist->entries)) {
162
+ if (list_empty(&evlist->core.entries)) {
212163 fprintf(stderr, "must define events before cgroups\n");
213164 return -1;
214165 }
....@@ -249,3 +200,180 @@
249200 }
250201 return 0;
251202 }
203
+
204
+int evlist__expand_cgroup(struct evlist *evlist, const char *str,
205
+ struct rblist *metric_events, bool open_cgroup)
206
+{
207
+ struct evlist *orig_list, *tmp_list;
208
+ struct evsel *pos, *evsel, *leader;
209
+ struct rblist orig_metric_events;
210
+ struct cgroup *cgrp = NULL;
211
+ const char *p, *e, *eos = str + strlen(str);
212
+ int ret = -1;
213
+
214
+ if (evlist->core.nr_entries == 0) {
215
+ fprintf(stderr, "must define events before cgroups\n");
216
+ return -EINVAL;
217
+ }
218
+
219
+ orig_list = evlist__new();
220
+ tmp_list = evlist__new();
221
+ if (orig_list == NULL || tmp_list == NULL) {
222
+ fprintf(stderr, "memory allocation failed\n");
223
+ return -ENOMEM;
224
+ }
225
+
226
+ /* save original events and init evlist */
227
+ perf_evlist__splice_list_tail(orig_list, &evlist->core.entries);
228
+ evlist->core.nr_entries = 0;
229
+
230
+ if (metric_events) {
231
+ orig_metric_events = *metric_events;
232
+ rblist__init(metric_events);
233
+ } else {
234
+ rblist__init(&orig_metric_events);
235
+ }
236
+
237
+ for (;;) {
238
+ p = strchr(str, ',');
239
+ e = p ? p : eos;
240
+
241
+ /* allow empty cgroups, i.e., skip */
242
+ if (e - str) {
243
+ /* termination added */
244
+ char *name = strndup(str, e - str);
245
+ if (!name)
246
+ goto out_err;
247
+
248
+ cgrp = cgroup__new(name, open_cgroup);
249
+ free(name);
250
+ if (cgrp == NULL)
251
+ goto out_err;
252
+ } else {
253
+ cgrp = NULL;
254
+ }
255
+
256
+ leader = NULL;
257
+ evlist__for_each_entry(orig_list, pos) {
258
+ evsel = evsel__clone(pos);
259
+ if (evsel == NULL)
260
+ goto out_err;
261
+
262
+ cgroup__put(evsel->cgrp);
263
+ evsel->cgrp = cgroup__get(cgrp);
264
+
265
+ if (evsel__is_group_leader(pos))
266
+ leader = evsel;
267
+ evsel->leader = leader;
268
+
269
+ evlist__add(tmp_list, evsel);
270
+ }
271
+ /* cgroup__new() has a refcount, release it here */
272
+ cgroup__put(cgrp);
273
+ nr_cgroups++;
274
+
275
+ if (metric_events) {
276
+ perf_stat__collect_metric_expr(tmp_list);
277
+ if (metricgroup__copy_metric_events(tmp_list, cgrp,
278
+ metric_events,
279
+ &orig_metric_events) < 0)
280
+ break;
281
+ }
282
+
283
+ perf_evlist__splice_list_tail(evlist, &tmp_list->core.entries);
284
+ tmp_list->core.nr_entries = 0;
285
+
286
+ if (!p) {
287
+ ret = 0;
288
+ break;
289
+ }
290
+ str = p+1;
291
+ }
292
+
293
+out_err:
294
+ evlist__delete(orig_list);
295
+ evlist__delete(tmp_list);
296
+ rblist__exit(&orig_metric_events);
297
+
298
+ return ret;
299
+}
300
+
301
+static struct cgroup *__cgroup__findnew(struct rb_root *root, uint64_t id,
302
+ bool create, const char *path)
303
+{
304
+ struct rb_node **p = &root->rb_node;
305
+ struct rb_node *parent = NULL;
306
+ struct cgroup *cgrp;
307
+
308
+ while (*p != NULL) {
309
+ parent = *p;
310
+ cgrp = rb_entry(parent, struct cgroup, node);
311
+
312
+ if (cgrp->id == id)
313
+ return cgrp;
314
+
315
+ if (cgrp->id < id)
316
+ p = &(*p)->rb_left;
317
+ else
318
+ p = &(*p)->rb_right;
319
+ }
320
+
321
+ if (!create)
322
+ return NULL;
323
+
324
+ cgrp = malloc(sizeof(*cgrp));
325
+ if (cgrp == NULL)
326
+ return NULL;
327
+
328
+ cgrp->name = strdup(path);
329
+ if (cgrp->name == NULL) {
330
+ free(cgrp);
331
+ return NULL;
332
+ }
333
+
334
+ cgrp->fd = -1;
335
+ cgrp->id = id;
336
+ refcount_set(&cgrp->refcnt, 1);
337
+
338
+ rb_link_node(&cgrp->node, parent, p);
339
+ rb_insert_color(&cgrp->node, root);
340
+
341
+ return cgrp;
342
+}
343
+
344
+struct cgroup *cgroup__findnew(struct perf_env *env, uint64_t id,
345
+ const char *path)
346
+{
347
+ struct cgroup *cgrp;
348
+
349
+ down_write(&env->cgroups.lock);
350
+ cgrp = __cgroup__findnew(&env->cgroups.tree, id, true, path);
351
+ up_write(&env->cgroups.lock);
352
+ return cgrp;
353
+}
354
+
355
+struct cgroup *cgroup__find(struct perf_env *env, uint64_t id)
356
+{
357
+ struct cgroup *cgrp;
358
+
359
+ down_read(&env->cgroups.lock);
360
+ cgrp = __cgroup__findnew(&env->cgroups.tree, id, false, NULL);
361
+ up_read(&env->cgroups.lock);
362
+ return cgrp;
363
+}
364
+
365
+void perf_env__purge_cgroups(struct perf_env *env)
366
+{
367
+ struct rb_node *node;
368
+ struct cgroup *cgrp;
369
+
370
+ down_write(&env->cgroups.lock);
371
+ while (!RB_EMPTY_ROOT(&env->cgroups.tree)) {
372
+ node = rb_first(&env->cgroups.tree);
373
+ cgrp = rb_entry(node, struct cgroup, node);
374
+
375
+ rb_erase(node, &env->cgroups.tree);
376
+ cgroup__put(cgrp);
377
+ }
378
+ up_write(&env->cgroups.lock);
379
+}