Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cgroup.c
Go to the documentation of this file.
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 
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 }