Linux Audio

Check our new training course

Embedded Linux training

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