root/tools/perf/util/cgroup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cgroupfs_find_mountpoint
  2. open_cgroup
  3. evlist__find_cgroup
  4. cgroup__new
  5. evlist__findnew_cgroup
  6. add_cgroup
  7. cgroup__delete
  8. cgroup__put
  9. cgroup__get
  10. evsel__set_default_cgroup
  11. evlist__set_default_cgroup
  12. parse_cgroups

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <subcmd/parse-options.h>
   3 #include "evsel.h"
   4 #include "cgroup.h"
   5 #include "evlist.h"
   6 #include <linux/stringify.h>
   7 #include <linux/zalloc.h>
   8 #include <sys/types.h>
   9 #include <sys/stat.h>
  10 #include <fcntl.h>
  11 #include <stdlib.h>
  12 #include <string.h>
  13 
  14 int nr_cgroups;
  15 
  16 static int
  17 cgroupfs_find_mountpoint(char *buf, size_t maxlen)
  18 {
  19         FILE *fp;
  20         char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
  21         char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
  22         char *token, *saved_ptr = NULL;
  23 
  24         fp = fopen("/proc/mounts", "r");
  25         if (!fp)
  26                 return -1;
  27 
  28         /*
  29          * in order to handle split hierarchy, we need to scan /proc/mounts
  30          * and inspect every cgroupfs mount point to find one that has
  31          * perf_event subsystem
  32          */
  33         path_v1[0] = '\0';
  34         path_v2[0] = '\0';
  35 
  36         while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
  37                                 __stringify(PATH_MAX)"s %*d %*d\n",
  38                                 mountpoint, type, tokens) == 3) {
  39 
  40                 if (!path_v1[0] && !strcmp(type, "cgroup")) {
  41 
  42                         token = strtok_r(tokens, ",", &saved_ptr);
  43 
  44                         while (token != NULL) {
  45                                 if (!strcmp(token, "perf_event")) {
  46                                         strcpy(path_v1, mountpoint);
  47                                         break;
  48                                 }
  49                                 token = strtok_r(NULL, ",", &saved_ptr);
  50                         }
  51                 }
  52 
  53                 if (!path_v2[0] && !strcmp(type, "cgroup2"))
  54                         strcpy(path_v2, mountpoint);
  55 
  56                 if (path_v1[0] && path_v2[0])
  57                         break;
  58         }
  59         fclose(fp);
  60 
  61         if (path_v1[0])
  62                 path = path_v1;
  63         else if (path_v2[0])
  64                 path = path_v2;
  65         else
  66                 return -1;
  67 
  68         if (strlen(path) < maxlen) {
  69                 strcpy(buf, path);
  70                 return 0;
  71         }
  72         return -1;
  73 }
  74 
  75 static int open_cgroup(const char *name)
  76 {
  77         char path[PATH_MAX + 1];
  78         char mnt[PATH_MAX + 1];
  79         int fd;
  80 
  81 
  82         if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
  83                 return -1;
  84 
  85         scnprintf(path, PATH_MAX, "%s/%s", mnt, name);
  86 
  87         fd = open(path, O_RDONLY);
  88         if (fd == -1)
  89                 fprintf(stderr, "no access to cgroup %s\n", path);
  90 
  91         return fd;
  92 }
  93 
  94 static struct cgroup *evlist__find_cgroup(struct evlist *evlist, const char *str)
  95 {
  96         struct evsel *counter;
  97         /*
  98          * check if cgrp is already defined, if so we reuse it
  99          */
 100         evlist__for_each_entry(evlist, counter) {
 101                 if (!counter->cgrp)
 102                         continue;
 103                 if (!strcmp(counter->cgrp->name, str))
 104                         return cgroup__get(counter->cgrp);
 105         }
 106 
 107         return NULL;
 108 }
 109 
 110 static struct cgroup *cgroup__new(const char *name)
 111 {
 112         struct cgroup *cgroup = zalloc(sizeof(*cgroup));
 113 
 114         if (cgroup != NULL) {
 115                 refcount_set(&cgroup->refcnt, 1);
 116 
 117                 cgroup->name = strdup(name);
 118                 if (!cgroup->name)
 119                         goto out_err;
 120                 cgroup->fd = open_cgroup(name);
 121                 if (cgroup->fd == -1)
 122                         goto out_free_name;
 123         }
 124 
 125         return cgroup;
 126 
 127 out_free_name:
 128         zfree(&cgroup->name);
 129 out_err:
 130         free(cgroup);
 131         return NULL;
 132 }
 133 
 134 struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name)
 135 {
 136         struct cgroup *cgroup = evlist__find_cgroup(evlist, name);
 137 
 138         return cgroup ?: cgroup__new(name);
 139 }
 140 
 141 static int add_cgroup(struct evlist *evlist, const char *str)
 142 {
 143         struct evsel *counter;
 144         struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str);
 145         int n;
 146 
 147         if (!cgrp)
 148                 return -1;
 149         /*
 150          * find corresponding event
 151          * if add cgroup N, then need to find event N
 152          */
 153         n = 0;
 154         evlist__for_each_entry(evlist, counter) {
 155                 if (n == nr_cgroups)
 156                         goto found;
 157                 n++;
 158         }
 159 
 160         cgroup__put(cgrp);
 161         return -1;
 162 found:
 163         counter->cgrp = cgrp;
 164         return 0;
 165 }
 166 
 167 static void cgroup__delete(struct cgroup *cgroup)
 168 {
 169         close(cgroup->fd);
 170         zfree(&cgroup->name);
 171         free(cgroup);
 172 }
 173 
 174 void cgroup__put(struct cgroup *cgrp)
 175 {
 176         if (cgrp && refcount_dec_and_test(&cgrp->refcnt)) {
 177                 cgroup__delete(cgrp);
 178         }
 179 }
 180 
 181 struct cgroup *cgroup__get(struct cgroup *cgroup)
 182 {
 183        if (cgroup)
 184                 refcount_inc(&cgroup->refcnt);
 185        return cgroup;
 186 }
 187 
 188 static void evsel__set_default_cgroup(struct evsel *evsel, struct cgroup *cgroup)
 189 {
 190         if (evsel->cgrp == NULL)
 191                 evsel->cgrp = cgroup__get(cgroup);
 192 }
 193 
 194 void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup)
 195 {
 196         struct evsel *evsel;
 197 
 198         evlist__for_each_entry(evlist, evsel)
 199                 evsel__set_default_cgroup(evsel, cgroup);
 200 }
 201 
 202 int parse_cgroups(const struct option *opt, const char *str,
 203                   int unset __maybe_unused)
 204 {
 205         struct evlist *evlist = *(struct evlist **)opt->value;
 206         struct evsel *counter;
 207         struct cgroup *cgrp = NULL;
 208         const char *p, *e, *eos = str + strlen(str);
 209         char *s;
 210         int ret, i;
 211 
 212         if (list_empty(&evlist->core.entries)) {
 213                 fprintf(stderr, "must define events before cgroups\n");
 214                 return -1;
 215         }
 216 
 217         for (;;) {
 218                 p = strchr(str, ',');
 219                 e = p ? p : eos;
 220 
 221                 /* allow empty cgroups, i.e., skip */
 222                 if (e - str) {
 223                         /* termination added */
 224                         s = strndup(str, e - str);
 225                         if (!s)
 226                                 return -1;
 227                         ret = add_cgroup(evlist, s);
 228                         free(s);
 229                         if (ret)
 230                                 return -1;
 231                 }
 232                 /* nr_cgroups is increased een for empty cgroups */
 233                 nr_cgroups++;
 234                 if (!p)
 235                         break;
 236                 str = p+1;
 237         }
 238         /* for the case one cgroup combine to multiple events */
 239         i = 0;
 240         if (nr_cgroups == 1) {
 241                 evlist__for_each_entry(evlist, counter) {
 242                         if (i == 0)
 243                                 cgrp = counter->cgrp;
 244                         else {
 245                                 counter->cgrp = cgrp;
 246                                 refcount_inc(&cgrp->refcnt);
 247                         }
 248                         i++;
 249                 }
 250         }
 251         return 0;
 252 }

/* [<][>][^][v][top][bottom][index][help] */