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 "evlist.h"
      7 
      8 int nr_cgroups;
      9 
     10 static int
     11 cgroupfs_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 
     57 static 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 
     76 static 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 	list_for_each_entry(counter, &evlist->entries, node) {
     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 	list_for_each_entry(counter, &evlist->entries, node) {
    114 		if (n == nr_cgroups)
    115 			goto found;
    116 		n++;
    117 	}
    118 	if (cgrp->refcnt == 0)
    119 		free(cgrp);
    120 
    121 	return -1;
    122 found:
    123 	cgrp->refcnt++;
    124 	counter->cgrp = cgrp;
    125 	return 0;
    126 }
    127 
    128 void close_cgroup(struct cgroup_sel *cgrp)
    129 {
    130 	if (!cgrp)
    131 		return;
    132 
    133 	/* XXX: not reentrant */
    134 	if (--cgrp->refcnt == 0) {
    135 		close(cgrp->fd);
    136 		free(cgrp->name);
    137 		free(cgrp);
    138 	}
    139 }
    140 
    141 int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
    142 		  int unset __maybe_unused)
    143 {
    144 	struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
    145 	const char *p, *e, *eos = str + strlen(str);
    146 	char *s;
    147 	int ret;
    148 
    149 	if (list_empty(&evlist->entries)) {
    150 		fprintf(stderr, "must define events before cgroups\n");
    151 		return -1;
    152 	}
    153 
    154 	for (;;) {
    155 		p = strchr(str, ',');
    156 		e = p ? p : eos;
    157 
    158 		/* allow empty cgroups, i.e., skip */
    159 		if (e - str) {
    160 			/* termination added */
    161 			s = strndup(str, e - str);
    162 			if (!s)
    163 				return -1;
    164 			ret = add_cgroup(evlist, s);
    165 			if (ret) {
    166 				free(s);
    167 				return -1;
    168 			}
    169 		}
    170 		/* nr_cgroups is increased een for empty cgroups */
    171 		nr_cgroups++;
    172 		if (!p)
    173 			break;
    174 		str = p+1;
    175 	}
    176 	return 0;
    177 }
    178