summaryrefslogtreecommitdiff
path: root/tools/perf/util/cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/cgroup.c')
-rw-r--r--tools/perf/util/cgroup.c128
1 files changed, 95 insertions, 33 deletions
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 984f69144f87..decb91f9da82 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -71,7 +71,7 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen)
return -1;
}
-static int open_cgroup(char *name)
+static int open_cgroup(const char *name)
{
char path[PATH_MAX + 1];
char mnt[PATH_MAX + 1];
@@ -81,7 +81,7 @@ static int open_cgroup(char *name)
if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
return -1;
- snprintf(path, PATH_MAX, "%s/%s", mnt, name);
+ scnprintf(path, PATH_MAX, "%s/%s", mnt, name);
fd = open(path, O_RDONLY);
if (fd == -1)
@@ -90,41 +90,64 @@ static int open_cgroup(char *name)
return fd;
}
-static int add_cgroup(struct perf_evlist *evlist, char *str)
+static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str)
{
struct perf_evsel *counter;
- struct cgroup_sel *cgrp = NULL;
- int n;
+ struct cgroup *cgrp = NULL;
/*
* check if cgrp is already defined, if so we reuse it
*/
evlist__for_each_entry(evlist, counter) {
- cgrp = counter->cgrp;
- if (!cgrp)
+ if (!counter->cgrp)
continue;
- if (!strcmp(cgrp->name, str)) {
- refcount_inc(&cgrp->refcnt);
+ if (!strcmp(counter->cgrp->name, str)) {
+ cgrp = cgroup__get(counter->cgrp);
break;
}
-
- cgrp = NULL;
}
- if (!cgrp) {
- cgrp = zalloc(sizeof(*cgrp));
- if (!cgrp)
- return -1;
+ return cgrp;
+}
- cgrp->name = str;
- refcount_set(&cgrp->refcnt, 1);
+static struct cgroup *cgroup__new(const char *name)
+{
+ struct cgroup *cgroup = zalloc(sizeof(*cgroup));
- cgrp->fd = open_cgroup(str);
- if (cgrp->fd == -1) {
- free(cgrp);
- return -1;
- }
+ if (cgroup != NULL) {
+ refcount_set(&cgroup->refcnt, 1);
+
+ cgroup->name = strdup(name);
+ if (!cgroup->name)
+ goto out_err;
+ cgroup->fd = open_cgroup(name);
+ if (cgroup->fd == -1)
+ goto out_free_name;
}
+ return cgroup;
+
+out_free_name:
+ free(cgroup->name);
+out_err:
+ free(cgroup);
+ return NULL;
+}
+
+struct cgroup *evlist__findnew_cgroup(struct perf_evlist *evlist, const char *name)
+{
+ struct cgroup *cgroup = evlist__find_cgroup(evlist, name);
+
+ return cgroup ?: cgroup__new(name);
+}
+
+static int add_cgroup(struct perf_evlist *evlist, const char *str)
+{
+ struct perf_evsel *counter;
+ struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str);
+ int n;
+
+ if (!cgrp)
+ return -1;
/*
* find corresponding event
* if add cgroup N, then need to find event N
@@ -135,31 +158,58 @@ static int add_cgroup(struct perf_evlist *evlist, char *str)
goto found;
n++;
}
- if (refcount_dec_and_test(&cgrp->refcnt))
- free(cgrp);
+ cgroup__put(cgrp);
return -1;
found:
counter->cgrp = cgrp;
return 0;
}
-void close_cgroup(struct cgroup_sel *cgrp)
+static void cgroup__delete(struct cgroup *cgroup)
+{
+ close(cgroup->fd);
+ zfree(&cgroup->name);
+ free(cgroup);
+}
+
+void cgroup__put(struct cgroup *cgrp)
{
if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
- close(cgrp->fd);
- zfree(&cgrp->name);
- free(cgrp);
+ cgroup__delete(cgrp);
}
}
-int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
+struct cgroup *cgroup__get(struct cgroup *cgroup)
+{
+ if (cgroup)
+ refcount_inc(&cgroup->refcnt);
+ return cgroup;
+}
+
+static void evsel__set_default_cgroup(struct perf_evsel *evsel, struct cgroup *cgroup)
+{
+ if (evsel->cgrp == NULL)
+ evsel->cgrp = cgroup__get(cgroup);
+}
+
+void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgroup)
+{
+ struct perf_evsel *evsel;
+
+ evlist__for_each_entry(evlist, evsel)
+ evsel__set_default_cgroup(evsel, cgroup);
+}
+
+int parse_cgroups(const struct option *opt, const char *str,
int unset __maybe_unused)
{
struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
+ struct perf_evsel *counter;
+ struct cgroup *cgrp = NULL;
const char *p, *e, *eos = str + strlen(str);
char *s;
- int ret;
+ int ret, i;
if (list_empty(&evlist->entries)) {
fprintf(stderr, "must define events before cgroups\n");
@@ -177,10 +227,9 @@ int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
if (!s)
return -1;
ret = add_cgroup(evlist, s);
- if (ret) {
- free(s);
+ free(s);
+ if (ret)
return -1;
- }
}
/* nr_cgroups is increased een for empty cgroups */
nr_cgroups++;
@@ -188,5 +237,18 @@ int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
break;
str = p+1;
}
+ /* for the case one cgroup combine to multiple events */
+ i = 0;
+ if (nr_cgroups == 1) {
+ evlist__for_each_entry(evlist, counter) {
+ if (i == 0)
+ cgrp = counter->cgrp;
+ else {
+ counter->cgrp = cgrp;
+ refcount_inc(&cgrp->refcnt);
+ }
+ i++;
+ }
+ }
return 0;
}