cgroup.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. int nr_cgroups;
  8. static int
  9. cgroupfs_find_mountpoint(char *buf, size_t maxlen)
  10. {
  11. FILE *fp;
  12. char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
  13. char *token, *saved_ptr = NULL;
  14. int found = 0;
  15. fp = fopen("/proc/mounts", "r");
  16. if (!fp)
  17. return -1;
  18. /*
  19. * in order to handle split hierarchy, we need to scan /proc/mounts
  20. * and inspect every cgroupfs mount point to find one that has
  21. * perf_event subsystem
  22. */
  23. while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %"
  24. STR(PATH_MAX)"s %*d %*d\n",
  25. mountpoint, type, tokens) == 3) {
  26. if (!strcmp(type, "cgroup")) {
  27. token = strtok_r(tokens, ",", &saved_ptr);
  28. while (token != NULL) {
  29. if (!strcmp(token, "perf_event")) {
  30. found = 1;
  31. break;
  32. }
  33. token = strtok_r(NULL, ",", &saved_ptr);
  34. }
  35. }
  36. if (found)
  37. break;
  38. }
  39. fclose(fp);
  40. if (!found)
  41. return -1;
  42. if (strlen(mountpoint) < maxlen) {
  43. strcpy(buf, mountpoint);
  44. return 0;
  45. }
  46. return -1;
  47. }
  48. static int open_cgroup(char *name)
  49. {
  50. char path[PATH_MAX + 1];
  51. char mnt[PATH_MAX + 1];
  52. int fd;
  53. if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
  54. return -1;
  55. snprintf(path, PATH_MAX, "%s/%s", mnt, name);
  56. fd = open(path, O_RDONLY);
  57. if (fd == -1)
  58. fprintf(stderr, "no access to cgroup %s\n", path);
  59. return fd;
  60. }
  61. static int add_cgroup(struct perf_evlist *evlist, char *str)
  62. {
  63. struct perf_evsel *counter;
  64. struct cgroup_sel *cgrp = NULL;
  65. int n;
  66. /*
  67. * check if cgrp is already defined, if so we reuse it
  68. */
  69. evlist__for_each(evlist, counter) {
  70. cgrp = counter->cgrp;
  71. if (!cgrp)
  72. continue;
  73. if (!strcmp(cgrp->name, str))
  74. break;
  75. cgrp = NULL;
  76. }
  77. if (!cgrp) {
  78. cgrp = zalloc(sizeof(*cgrp));
  79. if (!cgrp)
  80. return -1;
  81. cgrp->name = str;
  82. cgrp->fd = open_cgroup(str);
  83. if (cgrp->fd == -1) {
  84. free(cgrp);
  85. return -1;
  86. }
  87. }
  88. /*
  89. * find corresponding event
  90. * if add cgroup N, then need to find event N
  91. */
  92. n = 0;
  93. evlist__for_each(evlist, counter) {
  94. if (n == nr_cgroups)
  95. goto found;
  96. n++;
  97. }
  98. if (atomic_read(&cgrp->refcnt) == 0)
  99. free(cgrp);
  100. return -1;
  101. found:
  102. atomic_inc(&cgrp->refcnt);
  103. counter->cgrp = cgrp;
  104. return 0;
  105. }
  106. void close_cgroup(struct cgroup_sel *cgrp)
  107. {
  108. if (cgrp && atomic_dec_and_test(&cgrp->refcnt)) {
  109. close(cgrp->fd);
  110. zfree(&cgrp->name);
  111. free(cgrp);
  112. }
  113. }
  114. int parse_cgroups(const struct option *opt __maybe_unused, const char *str,
  115. int unset __maybe_unused)
  116. {
  117. struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
  118. const char *p, *e, *eos = str + strlen(str);
  119. char *s;
  120. int ret;
  121. if (list_empty(&evlist->entries)) {
  122. fprintf(stderr, "must define events before cgroups\n");
  123. return -1;
  124. }
  125. for (;;) {
  126. p = strchr(str, ',');
  127. e = p ? p : eos;
  128. /* allow empty cgroups, i.e., skip */
  129. if (e - str) {
  130. /* termination added */
  131. s = strndup(str, e - str);
  132. if (!s)
  133. return -1;
  134. ret = add_cgroup(evlist, s);
  135. if (ret) {
  136. free(s);
  137. return -1;
  138. }
  139. }
  140. /* nr_cgroups is increased een for empty cgroups */
  141. nr_cgroups++;
  142. if (!p)
  143. break;
  144. str = p+1;
  145. }
  146. return 0;
  147. }