]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blame - tools/perf/util/cgroup.c
License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[mirror_ubuntu-eoan-kernel.git] / tools / perf / util / cgroup.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
023695d9
SE
2#include "util.h"
3#include "../perf.h"
4b6ab94e 4#include <subcmd/parse-options.h>
023695d9
SE
5#include "evsel.h"
6#include "cgroup.h"
023695d9 7#include "evlist.h"
aa8cc2f6 8#include <linux/stringify.h>
023695d9
SE
9
10int nr_cgroups;
11
12static int
13cgroupfs_find_mountpoint(char *buf, size_t maxlen)
14{
15 FILE *fp;
c168fbfb 16 char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
968ebff1 17 char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
621d2656 18 char *token, *saved_ptr = NULL;
023695d9
SE
19
20 fp = fopen("/proc/mounts", "r");
21 if (!fp)
22 return -1;
23
24 /*
25 * in order to handle split hierarchy, we need to scan /proc/mounts
26 * and inspect every cgroupfs mount point to find one that has
27 * perf_event subsystem
28 */
968ebff1
TH
29 path_v1[0] = '\0';
30 path_v2[0] = '\0';
31
aa8cc2f6
ACM
32 while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
33 __stringify(PATH_MAX)"s %*d %*d\n",
023695d9
SE
34 mountpoint, type, tokens) == 3) {
35
968ebff1 36 if (!path_v1[0] && !strcmp(type, "cgroup")) {
023695d9
SE
37
38 token = strtok_r(tokens, ",", &saved_ptr);
39
40 while (token != NULL) {
41 if (!strcmp(token, "perf_event")) {
968ebff1 42 strcpy(path_v1, mountpoint);
023695d9
SE
43 break;
44 }
45 token = strtok_r(NULL, ",", &saved_ptr);
46 }
47 }
968ebff1
TH
48
49 if (!path_v2[0] && !strcmp(type, "cgroup2"))
50 strcpy(path_v2, mountpoint);
51
52 if (path_v1[0] && path_v2[0])
023695d9
SE
53 break;
54 }
55 fclose(fp);
968ebff1
TH
56
57 if (path_v1[0])
58 path = path_v1;
59 else if (path_v2[0])
60 path = path_v2;
61 else
023695d9
SE
62 return -1;
63
968ebff1
TH
64 if (strlen(path) < maxlen) {
65 strcpy(buf, path);
023695d9
SE
66 return 0;
67 }
68 return -1;
69}
70
71static int open_cgroup(char *name)
72{
c168fbfb
ACM
73 char path[PATH_MAX + 1];
74 char mnt[PATH_MAX + 1];
023695d9
SE
75 int fd;
76
77
c168fbfb 78 if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
023695d9
SE
79 return -1;
80
c168fbfb 81 snprintf(path, PATH_MAX, "%s/%s", mnt, name);
023695d9
SE
82
83 fd = open(path, O_RDONLY);
84 if (fd == -1)
85 fprintf(stderr, "no access to cgroup %s\n", path);
86
87 return fd;
88}
89
90static int add_cgroup(struct perf_evlist *evlist, char *str)
91{
92 struct perf_evsel *counter;
93 struct cgroup_sel *cgrp = NULL;
94 int n;
95 /*
96 * check if cgrp is already defined, if so we reuse it
97 */
e5cadb93 98 evlist__for_each_entry(evlist, counter) {
023695d9
SE
99 cgrp = counter->cgrp;
100 if (!cgrp)
101 continue;
cd8dd032
ACM
102 if (!strcmp(cgrp->name, str)) {
103 refcount_inc(&cgrp->refcnt);
023695d9 104 break;
cd8dd032 105 }
023695d9
SE
106
107 cgrp = NULL;
108 }
109
110 if (!cgrp) {
111 cgrp = zalloc(sizeof(*cgrp));
112 if (!cgrp)
113 return -1;
114
115 cgrp->name = str;
cd8dd032 116 refcount_set(&cgrp->refcnt, 1);
023695d9
SE
117
118 cgrp->fd = open_cgroup(str);
119 if (cgrp->fd == -1) {
120 free(cgrp);
121 return -1;
122 }
123 }
124
125 /*
126 * find corresponding event
127 * if add cgroup N, then need to find event N
128 */
129 n = 0;
e5cadb93 130 evlist__for_each_entry(evlist, counter) {
023695d9
SE
131 if (n == nr_cgroups)
132 goto found;
133 n++;
134 }
cd8dd032 135 if (refcount_dec_and_test(&cgrp->refcnt))
023695d9
SE
136 free(cgrp);
137
138 return -1;
139found:
023695d9
SE
140 counter->cgrp = cgrp;
141 return 0;
142}
143
144void close_cgroup(struct cgroup_sel *cgrp)
145{
79c5fe6d 146 if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
023695d9 147 close(cgrp->fd);
74cf249d 148 zfree(&cgrp->name);
023695d9
SE
149 free(cgrp);
150 }
151}
152
1d037ca1
IT
153int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
154 int unset __maybe_unused)
023695d9
SE
155{
156 struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
157 const char *p, *e, *eos = str + strlen(str);
158 char *s;
159 int ret;
160
161 if (list_empty(&evlist->entries)) {
162 fprintf(stderr, "must define events before cgroups\n");
163 return -1;
164 }
165
166 for (;;) {
167 p = strchr(str, ',');
168 e = p ? p : eos;
169
170 /* allow empty cgroups, i.e., skip */
171 if (e - str) {
172 /* termination added */
173 s = strndup(str, e - str);
174 if (!s)
175 return -1;
176 ret = add_cgroup(evlist, s);
177 if (ret) {
178 free(s);
179 return -1;
180 }
181 }
182 /* nr_cgroups is increased een for empty cgroups */
183 nr_cgroups++;
184 if (!p)
185 break;
186 str = p+1;
187 }
188 return 0;
189}