Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 "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         evlist__for_each(evlist, counter) {
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         evlist__for_each(evlist, counter) {
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                 zfree(&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 }