linux/tools/perf/util/cgroup.c
<<
>>
Prefs
   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
   8int nr_cgroups;
   9
  10static int
  11cgroupfs_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
  57static 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
  76static 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;
 122found:
 123        cgrp->refcnt++;
 124        counter->cgrp = cgrp;
 125        return 0;
 126}
 127
 128void 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
 141int parse_cgroups(const struct option *opt __used, const char *str,
 142                  int unset __used)
 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