Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/tools/perf/util/cgroup.c
10821 views
1
#include "util.h"
2
#include "../perf.h"
3
#include "parse-options.h"
4
#include "evsel.h"
5
#include "cgroup.h"
6
#include "debugfs.h" /* MAX_PATH, STR() */
7
#include "evlist.h"
8
9
int nr_cgroups;
10
11
static int
12
cgroupfs_find_mountpoint(char *buf, size_t maxlen)
13
{
14
FILE *fp;
15
char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1];
16
char *token, *saved_ptr = NULL;
17
int found = 0;
18
19
fp = fopen("/proc/mounts", "r");
20
if (!fp)
21
return -1;
22
23
/*
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
27
*/
28
while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %"
29
STR(MAX_PATH)"s %*d %*d\n",
30
mountpoint, type, tokens) == 3) {
31
32
if (!strcmp(type, "cgroup")) {
33
34
token = strtok_r(tokens, ",", &saved_ptr);
35
36
while (token != NULL) {
37
if (!strcmp(token, "perf_event")) {
38
found = 1;
39
break;
40
}
41
token = strtok_r(NULL, ",", &saved_ptr);
42
}
43
}
44
if (found)
45
break;
46
}
47
fclose(fp);
48
if (!found)
49
return -1;
50
51
if (strlen(mountpoint) < maxlen) {
52
strcpy(buf, mountpoint);
53
return 0;
54
}
55
return -1;
56
}
57
58
static int open_cgroup(char *name)
59
{
60
char path[MAX_PATH+1];
61
char mnt[MAX_PATH+1];
62
int fd;
63
64
65
if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1))
66
return -1;
67
68
snprintf(path, MAX_PATH, "%s/%s", mnt, name);
69
70
fd = open(path, O_RDONLY);
71
if (fd == -1)
72
fprintf(stderr, "no access to cgroup %s\n", path);
73
74
return fd;
75
}
76
77
static int add_cgroup(struct perf_evlist *evlist, char *str)
78
{
79
struct perf_evsel *counter;
80
struct cgroup_sel *cgrp = NULL;
81
int n;
82
/*
83
* check if cgrp is already defined, if so we reuse it
84
*/
85
list_for_each_entry(counter, &evlist->entries, node) {
86
cgrp = counter->cgrp;
87
if (!cgrp)
88
continue;
89
if (!strcmp(cgrp->name, str))
90
break;
91
92
cgrp = NULL;
93
}
94
95
if (!cgrp) {
96
cgrp = zalloc(sizeof(*cgrp));
97
if (!cgrp)
98
return -1;
99
100
cgrp->name = str;
101
102
cgrp->fd = open_cgroup(str);
103
if (cgrp->fd == -1) {
104
free(cgrp);
105
return -1;
106
}
107
}
108
109
/*
110
* find corresponding event
111
* if add cgroup N, then need to find event N
112
*/
113
n = 0;
114
list_for_each_entry(counter, &evlist->entries, node) {
115
if (n == nr_cgroups)
116
goto found;
117
n++;
118
}
119
if (cgrp->refcnt == 0)
120
free(cgrp);
121
122
return -1;
123
found:
124
cgrp->refcnt++;
125
counter->cgrp = cgrp;
126
return 0;
127
}
128
129
void close_cgroup(struct cgroup_sel *cgrp)
130
{
131
if (!cgrp)
132
return;
133
134
/* XXX: not reentrant */
135
if (--cgrp->refcnt == 0) {
136
close(cgrp->fd);
137
free(cgrp->name);
138
free(cgrp);
139
}
140
}
141
142
int parse_cgroups(const struct option *opt __used, const char *str,
143
int unset __used)
144
{
145
struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
146
const char *p, *e, *eos = str + strlen(str);
147
char *s;
148
int ret;
149
150
if (list_empty(&evlist->entries)) {
151
fprintf(stderr, "must define events before cgroups\n");
152
return -1;
153
}
154
155
for (;;) {
156
p = strchr(str, ',');
157
e = p ? p : eos;
158
159
/* allow empty cgroups, i.e., skip */
160
if (e - str) {
161
/* termination added */
162
s = strndup(str, e - str);
163
if (!s)
164
return -1;
165
ret = add_cgroup(evlist, s);
166
if (ret) {
167
free(s);
168
return -1;
169
}
170
}
171
/* nr_cgroups is increased een for empty cgroups */
172
nr_cgroups++;
173
if (!p)
174
break;
175
str = p+1;
176
}
177
return 0;
178
}
179
180