 0050f7aa18
			
		
	
	
	0050f7aa18
	
	
	
		
			
			For the common evsel list traversal, so that it becomes more compact. Use the opportunity to start ditching the 'perf_' from 'perf_evlist__', as discussed, as the whole conversion touches a lot of places, lets do it piecemeal when we have the chance due to other work, like in this case. Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-qnkx7dzm2h6m6uptkfk03ni6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
		
			
				
	
	
		
			177 lines
		
	
	
	
		
			3.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
	
		
			3.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "util.h"
 | |
| #include "../perf.h"
 | |
| #include "parse-options.h"
 | |
| #include "evsel.h"
 | |
| #include "cgroup.h"
 | |
| #include "evlist.h"
 | |
| 
 | |
| int nr_cgroups;
 | |
| 
 | |
| static int
 | |
| cgroupfs_find_mountpoint(char *buf, size_t maxlen)
 | |
| {
 | |
| 	FILE *fp;
 | |
| 	char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
 | |
| 	char *token, *saved_ptr = NULL;
 | |
| 	int found = 0;
 | |
| 
 | |
| 	fp = fopen("/proc/mounts", "r");
 | |
| 	if (!fp)
 | |
| 		return -1;
 | |
| 
 | |
| 	/*
 | |
| 	 * in order to handle split hierarchy, we need to scan /proc/mounts
 | |
| 	 * and inspect every cgroupfs mount point to find one that has
 | |
| 	 * perf_event subsystem
 | |
| 	 */
 | |
| 	while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %"
 | |
| 				STR(PATH_MAX)"s %*d %*d\n",
 | |
| 				mountpoint, type, tokens) == 3) {
 | |
| 
 | |
| 		if (!strcmp(type, "cgroup")) {
 | |
| 
 | |
| 			token = strtok_r(tokens, ",", &saved_ptr);
 | |
| 
 | |
| 			while (token != NULL) {
 | |
| 				if (!strcmp(token, "perf_event")) {
 | |
| 					found = 1;
 | |
| 					break;
 | |
| 				}
 | |
| 				token = strtok_r(NULL, ",", &saved_ptr);
 | |
| 			}
 | |
| 		}
 | |
| 		if (found)
 | |
| 			break;
 | |
| 	}
 | |
| 	fclose(fp);
 | |
| 	if (!found)
 | |
| 		return -1;
 | |
| 
 | |
| 	if (strlen(mountpoint) < maxlen) {
 | |
| 		strcpy(buf, mountpoint);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| static int open_cgroup(char *name)
 | |
| {
 | |
| 	char path[PATH_MAX + 1];
 | |
| 	char mnt[PATH_MAX + 1];
 | |
| 	int fd;
 | |
| 
 | |
| 
 | |
| 	if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
 | |
| 		return -1;
 | |
| 
 | |
| 	snprintf(path, PATH_MAX, "%s/%s", mnt, name);
 | |
| 
 | |
| 	fd = open(path, O_RDONLY);
 | |
| 	if (fd == -1)
 | |
| 		fprintf(stderr, "no access to cgroup %s\n", path);
 | |
| 
 | |
| 	return fd;
 | |
| }
 | |
| 
 | |
| static int add_cgroup(struct perf_evlist *evlist, char *str)
 | |
| {
 | |
| 	struct perf_evsel *counter;
 | |
| 	struct cgroup_sel *cgrp = NULL;
 | |
| 	int n;
 | |
| 	/*
 | |
| 	 * check if cgrp is already defined, if so we reuse it
 | |
| 	 */
 | |
| 	evlist__for_each(evlist, counter) {
 | |
| 		cgrp = counter->cgrp;
 | |
| 		if (!cgrp)
 | |
| 			continue;
 | |
| 		if (!strcmp(cgrp->name, str))
 | |
| 			break;
 | |
| 
 | |
| 		cgrp = NULL;
 | |
| 	}
 | |
| 
 | |
| 	if (!cgrp) {
 | |
| 		cgrp = zalloc(sizeof(*cgrp));
 | |
| 		if (!cgrp)
 | |
| 			return -1;
 | |
| 
 | |
| 		cgrp->name = str;
 | |
| 
 | |
| 		cgrp->fd = open_cgroup(str);
 | |
| 		if (cgrp->fd == -1) {
 | |
| 			free(cgrp);
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * find corresponding event
 | |
| 	 * if add cgroup N, then need to find event N
 | |
| 	 */
 | |
| 	n = 0;
 | |
| 	evlist__for_each(evlist, counter) {
 | |
| 		if (n == nr_cgroups)
 | |
| 			goto found;
 | |
| 		n++;
 | |
| 	}
 | |
| 	if (cgrp->refcnt == 0)
 | |
| 		free(cgrp);
 | |
| 
 | |
| 	return -1;
 | |
| found:
 | |
| 	cgrp->refcnt++;
 | |
| 	counter->cgrp = cgrp;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void close_cgroup(struct cgroup_sel *cgrp)
 | |
| {
 | |
| 	if (!cgrp)
 | |
| 		return;
 | |
| 
 | |
| 	/* XXX: not reentrant */
 | |
| 	if (--cgrp->refcnt == 0) {
 | |
| 		close(cgrp->fd);
 | |
| 		zfree(&cgrp->name);
 | |
| 		free(cgrp);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
 | |
| 		  int unset __maybe_unused)
 | |
| {
 | |
| 	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
 | |
| 	const char *p, *e, *eos = str + strlen(str);
 | |
| 	char *s;
 | |
| 	int ret;
 | |
| 
 | |
| 	if (list_empty(&evlist->entries)) {
 | |
| 		fprintf(stderr, "must define events before cgroups\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	for (;;) {
 | |
| 		p = strchr(str, ',');
 | |
| 		e = p ? p : eos;
 | |
| 
 | |
| 		/* allow empty cgroups, i.e., skip */
 | |
| 		if (e - str) {
 | |
| 			/* termination added */
 | |
| 			s = strndup(str, e - str);
 | |
| 			if (!s)
 | |
| 				return -1;
 | |
| 			ret = add_cgroup(evlist, s);
 | |
| 			if (ret) {
 | |
| 				free(s);
 | |
| 				return -1;
 | |
| 			}
 | |
| 		}
 | |
| 		/* nr_cgroups is increased een for empty cgroups */
 | |
| 		nr_cgroups++;
 | |
| 		if (!p)
 | |
| 			break;
 | |
| 		str = p+1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 |