Home | History | Annotate | Download | only in util
      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