perf_api_probe.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #include "perf-sys.h"
  3. #include "util/cloexec.h"
  4. #include "util/evlist.h"
  5. #include "util/evsel.h"
  6. #include "util/parse-events.h"
  7. #include "util/perf_api_probe.h"
  8. #include <perf/cpumap.h>
  9. #include <errno.h>
  10. typedef void (*setup_probe_fn_t)(struct evsel *evsel);
  11. static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str)
  12. {
  13. struct evlist *evlist;
  14. struct evsel *evsel;
  15. unsigned long flags = perf_event_open_cloexec_flag();
  16. int err = -EAGAIN, fd;
  17. static pid_t pid = -1;
  18. evlist = evlist__new();
  19. if (!evlist)
  20. return -ENOMEM;
  21. if (parse_event(evlist, str))
  22. goto out_delete;
  23. evsel = evlist__first(evlist);
  24. while (1) {
  25. fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
  26. if (fd < 0) {
  27. if (pid == -1 && errno == EACCES) {
  28. pid = 0;
  29. continue;
  30. }
  31. goto out_delete;
  32. }
  33. break;
  34. }
  35. close(fd);
  36. fn(evsel);
  37. fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
  38. if (fd < 0) {
  39. if (errno == EINVAL)
  40. err = -EINVAL;
  41. goto out_delete;
  42. }
  43. close(fd);
  44. err = 0;
  45. out_delete:
  46. evlist__delete(evlist);
  47. return err;
  48. }
  49. static bool perf_probe_api(setup_probe_fn_t fn)
  50. {
  51. struct perf_pmu *pmu;
  52. struct perf_cpu_map *cpus;
  53. struct perf_cpu cpu;
  54. int ret = 0;
  55. cpus = perf_cpu_map__new_online_cpus();
  56. if (!cpus)
  57. return false;
  58. cpu = perf_cpu_map__cpu(cpus, 0);
  59. perf_cpu_map__put(cpus);
  60. ret = perf_do_probe_api(fn, cpu, "software/cpu-clock/u");
  61. if (!ret)
  62. return true;
  63. pmu = perf_pmus__scan_core(/*pmu=*/NULL);
  64. if (pmu) {
  65. const char *try[] = {"cycles", "instructions", NULL};
  66. char buf[256];
  67. int i = 0;
  68. while (ret == -EAGAIN && try[i]) {
  69. snprintf(buf, sizeof(buf), "%s/%s/u", pmu->name, try[i++]);
  70. ret = perf_do_probe_api(fn, cpu, buf);
  71. if (!ret)
  72. return true;
  73. }
  74. }
  75. return false;
  76. }
  77. static void perf_probe_sample_identifier(struct evsel *evsel)
  78. {
  79. evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
  80. }
  81. static void perf_probe_comm_exec(struct evsel *evsel)
  82. {
  83. evsel->core.attr.comm_exec = 1;
  84. }
  85. static void perf_probe_context_switch(struct evsel *evsel)
  86. {
  87. evsel->core.attr.context_switch = 1;
  88. }
  89. static void perf_probe_text_poke(struct evsel *evsel)
  90. {
  91. evsel->core.attr.text_poke = 1;
  92. }
  93. static void perf_probe_build_id(struct evsel *evsel)
  94. {
  95. evsel->core.attr.build_id = 1;
  96. }
  97. static void perf_probe_cgroup(struct evsel *evsel)
  98. {
  99. evsel->core.attr.cgroup = 1;
  100. }
  101. bool perf_can_sample_identifier(void)
  102. {
  103. return perf_probe_api(perf_probe_sample_identifier);
  104. }
  105. bool perf_can_comm_exec(void)
  106. {
  107. return perf_probe_api(perf_probe_comm_exec);
  108. }
  109. bool perf_can_record_switch_events(void)
  110. {
  111. return perf_probe_api(perf_probe_context_switch);
  112. }
  113. bool perf_can_record_text_poke_events(void)
  114. {
  115. return perf_probe_api(perf_probe_text_poke);
  116. }
  117. bool perf_can_record_cpu_wide(void)
  118. {
  119. struct perf_event_attr attr = {
  120. .type = PERF_TYPE_SOFTWARE,
  121. .config = PERF_COUNT_SW_CPU_CLOCK,
  122. .exclude_kernel = 1,
  123. };
  124. struct perf_cpu_map *cpus;
  125. struct perf_cpu cpu;
  126. int fd;
  127. cpus = perf_cpu_map__new_online_cpus();
  128. if (!cpus)
  129. return false;
  130. cpu = perf_cpu_map__cpu(cpus, 0);
  131. perf_cpu_map__put(cpus);
  132. fd = sys_perf_event_open(&attr, -1, cpu.cpu, -1, 0);
  133. if (fd < 0)
  134. return false;
  135. close(fd);
  136. return true;
  137. }
  138. /*
  139. * Architectures are expected to know if AUX area sampling is supported by the
  140. * hardware. Here we check for kernel support.
  141. */
  142. bool perf_can_aux_sample(void)
  143. {
  144. struct perf_event_attr attr = {
  145. .size = sizeof(struct perf_event_attr),
  146. .exclude_kernel = 1,
  147. /*
  148. * Non-zero value causes the kernel to calculate the effective
  149. * attribute size up to that byte.
  150. */
  151. .aux_sample_size = 1,
  152. };
  153. int fd;
  154. fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
  155. /*
  156. * If the kernel attribute is big enough to contain aux_sample_size
  157. * then we assume that it is supported. We are relying on the kernel to
  158. * validate the attribute size before anything else that could be wrong.
  159. */
  160. if (fd < 0 && errno == E2BIG)
  161. return false;
  162. if (fd >= 0)
  163. close(fd);
  164. return true;
  165. }
  166. bool perf_can_record_build_id(void)
  167. {
  168. return perf_probe_api(perf_probe_build_id);
  169. }
  170. bool perf_can_record_cgroup(void)
  171. {
  172. return perf_probe_api(perf_probe_cgroup);
  173. }