cgroup.c 3.2 KB

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