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;
 | 
						|
}
 |