Linux Audio

Check our new training course

Loading...
v4.17
  1// SPDX-License-Identifier: GPL-2.0
  2#include "util.h"
  3#include "../perf.h"
  4#include <subcmd/parse-options.h>
  5#include "evsel.h"
  6#include "cgroup.h"
 
  7#include "evlist.h"
  8#include <linux/stringify.h>
  9#include <sys/types.h>
 10#include <sys/stat.h>
 11#include <fcntl.h>
 12
 13int nr_cgroups;
 14
 15static int
 16cgroupfs_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}
 73
 74static int open_cgroup(const char *name)
 75{
 76	char path[PATH_MAX + 1];
 77	char mnt[PATH_MAX + 1];
 78	int fd;
 79
 80
 81	if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
 82		return -1;
 83
 84	scnprintf(path, PATH_MAX, "%s/%s", mnt, name);
 85
 86	fd = open(path, O_RDONLY);
 87	if (fd == -1)
 88		fprintf(stderr, "no access to cgroup %s\n", path);
 89
 90	return fd;
 91}
 92
 93static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str)
 94{
 95	struct perf_evsel *counter;
 96	struct cgroup *cgrp = NULL;
 
 97	/*
 98	 * check if cgrp is already defined, if so we reuse it
 99	 */
100	evlist__for_each_entry(evlist, counter) {
101		if (!counter->cgrp)
 
102			continue;
103		if (!strcmp(counter->cgrp->name, str)) {
104			cgrp = cgroup__get(counter->cgrp);
105			break;
106		}
107	}
108
109	return cgrp;
110}
111
112static struct cgroup *cgroup__new(const char *name)
113{
114	struct cgroup *cgroup = zalloc(sizeof(*cgroup));
115
116	if (cgroup != NULL) {
117		refcount_set(&cgroup->refcnt, 1);
118
119		cgroup->name = strdup(name);
120		if (!cgroup->name)
121			goto out_err;
122		cgroup->fd = open_cgroup(name);
123		if (cgroup->fd == -1)
124			goto out_free_name;
125	}
126
127	return cgroup;
128
129out_free_name:
130	free(cgroup->name);
131out_err:
132	free(cgroup);
133	return NULL;
134}
135
136struct cgroup *evlist__findnew_cgroup(struct perf_evlist *evlist, const char *name)
137{
138	struct cgroup *cgroup = evlist__find_cgroup(evlist, name);
139
140	return cgroup ?: cgroup__new(name);
141}
142
143static int add_cgroup(struct perf_evlist *evlist, const char *str)
144{
145	struct perf_evsel *counter;
146	struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str);
147	int n;
 
148
149	if (!cgrp)
150		return -1;
151	/*
152	 * find corresponding event
153	 * if add cgroup N, then need to find event N
154	 */
155	n = 0;
156	evlist__for_each_entry(evlist, counter) {
157		if (n == nr_cgroups)
158			goto found;
159		n++;
160	}
 
 
161
162	cgroup__put(cgrp);
163	return -1;
164found:
 
165	counter->cgrp = cgrp;
166	return 0;
167}
168
169static void cgroup__delete(struct cgroup *cgroup)
170{
171	close(cgroup->fd);
172	zfree(&cgroup->name);
173	free(cgroup);
174}
175
176void cgroup__put(struct cgroup *cgrp)
177{
178	if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
179		cgroup__delete(cgrp);
 
180	}
181}
182
183struct cgroup *cgroup__get(struct cgroup *cgroup)
184{
185       if (cgroup)
186		refcount_inc(&cgroup->refcnt);
187       return cgroup;
188}
189
190static void evsel__set_default_cgroup(struct perf_evsel *evsel, struct cgroup *cgroup)
191{
192	if (evsel->cgrp == NULL)
193		evsel->cgrp = cgroup__get(cgroup);
194}
195
196void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgroup)
197{
198	struct perf_evsel *evsel;
199
200	evlist__for_each_entry(evlist, evsel)
201		evsel__set_default_cgroup(evsel, cgroup);
202}
203
204int parse_cgroups(const struct option *opt, const char *str,
205		  int unset __maybe_unused)
206{
207	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
208	struct perf_evsel *counter;
209	struct cgroup *cgrp = NULL;
210	const char *p, *e, *eos = str + strlen(str);
211	char *s;
212	int ret, i;
213
214	if (list_empty(&evlist->entries)) {
215		fprintf(stderr, "must define events before cgroups\n");
216		return -1;
217	}
218
219	for (;;) {
220		p = strchr(str, ',');
221		e = p ? p : eos;
222
223		/* allow empty cgroups, i.e., skip */
224		if (e - str) {
225			/* termination added */
226			s = strndup(str, e - str);
227			if (!s)
228				return -1;
229			ret = add_cgroup(evlist, s);
230			free(s);
231			if (ret)
232				return -1;
 
233		}
234		/* nr_cgroups is increased een for empty cgroups */
235		nr_cgroups++;
236		if (!p)
237			break;
238		str = p+1;
239	}
240	/* for the case one cgroup combine to multiple events */
241	i = 0;
242	if (nr_cgroups == 1) {
243		evlist__for_each_entry(evlist, counter) {
244			if (i == 0)
245				cgrp = counter->cgrp;
246			else {
247				counter->cgrp = cgrp;
248				refcount_inc(&cgrp->refcnt);
249			}
250			i++;
251		}
252	}
253	return 0;
254}
v3.1
 
  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
  9int nr_cgroups;
 10
 11static int
 12cgroupfs_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
 58static 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
 77static 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;
123found:
124	cgrp->refcnt++;
125	counter->cgrp = cgrp;
126	return 0;
127}
128
129void 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
142int 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}