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 "debugfs.h" /* MAX_PATH, STR() */
   7#include "evlist.h"
   8
   9int nr_cgroups;
  10
  11static int
  12cgroupfs_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
  58static 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
  77static 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;
 123found:
 124        cgrp->refcnt++;
 125        counter->cgrp = cgrp;
 126        return 0;
 127}
 128
 129void 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
 142int 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}
 179