Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1...
[pandora-kernel.git] / tools / perf / util / cgroup.c
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 }