linux/tools/perf/util/cgroup.c
<<
>>
Prefs
   1#include "util.h"
   2#include "../perf.h"
   3#include <subcmd/parse-options.h>
   4#include "evsel.h"
   5#include "cgroup.h"
   6#include "evlist.h"
   7#include <linux/stringify.h>
   8
   9int nr_cgroups;
  10
  11static int
  12cgroupfs_find_mountpoint(char *buf, size_t maxlen)
  13{
  14        FILE *fp;
  15        char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
  16        char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
  17        char *token, *saved_ptr = NULL;
  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        path_v1[0] = '\0';
  29        path_v2[0] = '\0';
  30
  31        while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
  32                                __stringify(PATH_MAX)"s %*d %*d\n",
  33                                mountpoint, type, tokens) == 3) {
  34
  35                if (!path_v1[0] && !strcmp(type, "cgroup")) {
  36
  37                        token = strtok_r(tokens, ",", &saved_ptr);
  38
  39                        while (token != NULL) {
  40                                if (!strcmp(token, "perf_event")) {
  41                                        strcpy(path_v1, mountpoint);
  42                                        break;
  43                                }
  44                                token = strtok_r(NULL, ",", &saved_ptr);
  45                        }
  46                }
  47
  48                if (!path_v2[0] && !strcmp(type, "cgroup2"))
  49                        strcpy(path_v2, mountpoint);
  50
  51                if (path_v1[0] && path_v2[0])
  52                        break;
  53        }
  54        fclose(fp);
  55
  56        if (path_v1[0])
  57                path = path_v1;
  58        else if (path_v2[0])
  59                path = path_v2;
  60        else
  61                return -1;
  62
  63        if (strlen(path) < maxlen) {
  64                strcpy(buf, path);
  65                return 0;
  66        }
  67        return -1;
  68}
  69
  70static int open_cgroup(char *name)
  71{
  72        char path[PATH_MAX + 1];
  73        char mnt[PATH_MAX + 1];
  74        int fd;
  75
  76
  77        if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
  78                return -1;
  79
  80        snprintf(path, PATH_MAX, "%s/%s", mnt, name);
  81
  82        fd = open(path, O_RDONLY);
  83        if (fd == -1)
  84                fprintf(stderr, "no access to cgroup %s\n", path);
  85
  86        return fd;
  87}
  88
  89static int add_cgroup(struct perf_evlist *evlist, char *str)
  90{
  91        struct perf_evsel *counter;
  92        struct cgroup_sel *cgrp = NULL;
  93        int n;
  94        /*
  95         * check if cgrp is already defined, if so we reuse it
  96         */
  97        evlist__for_each_entry(evlist, counter) {
  98                cgrp = counter->cgrp;
  99                if (!cgrp)
 100                        continue;
 101                if (!strcmp(cgrp->name, str))
 102                        break;
 103
 104                cgrp = NULL;
 105        }
 106
 107        if (!cgrp) {
 108                cgrp = zalloc(sizeof(*cgrp));
 109                if (!cgrp)
 110                        return -1;
 111
 112                cgrp->name = str;
 113
 114                cgrp->fd = open_cgroup(str);
 115                if (cgrp->fd == -1) {
 116                        free(cgrp);
 117                        return -1;
 118                }
 119        }
 120
 121        /*
 122         * find corresponding event
 123         * if add cgroup N, then need to find event N
 124         */
 125        n = 0;
 126        evlist__for_each_entry(evlist, counter) {
 127                if (n == nr_cgroups)
 128                        goto found;
 129                n++;
 130        }
 131        if (refcount_read(&cgrp->refcnt) == 0)
 132                free(cgrp);
 133
 134        return -1;
 135found:
 136        refcount_inc(&cgrp->refcnt);
 137        counter->cgrp = cgrp;
 138        return 0;
 139}
 140
 141void close_cgroup(struct cgroup_sel *cgrp)
 142{
 143        if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
 144                close(cgrp->fd);
 145                zfree(&cgrp->name);
 146                free(cgrp);
 147        }
 148}
 149
 150int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
 151                  int unset __maybe_unused)
 152{
 153        struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
 154        const char *p, *e, *eos = str + strlen(str);
 155        char *s;
 156        int ret;
 157
 158        if (list_empty(&evlist->entries)) {
 159                fprintf(stderr, "must define events before cgroups\n");
 160                return -1;
 161        }
 162
 163        for (;;) {
 164                p = strchr(str, ',');
 165                e = p ? p : eos;
 166
 167                /* allow empty cgroups, i.e., skip */
 168                if (e - str) {
 169                        /* termination added */
 170                        s = strndup(str, e - str);
 171                        if (!s)
 172                                return -1;
 173                        ret = add_cgroup(evlist, s);
 174                        if (ret) {
 175                                free(s);
 176                                return -1;
 177                        }
 178                }
 179                /* nr_cgroups is increased een for empty cgroups */
 180                nr_cgroups++;
 181                if (!p)
 182                        break;
 183                str = p+1;
 184        }
 185        return 0;
 186}
 187