0001
0002
0003 #include "perf-sys.h"
0004 #include "util/cloexec.h"
0005 #include "util/evlist.h"
0006 #include "util/evsel.h"
0007 #include "util/parse-events.h"
0008 #include "util/perf_api_probe.h"
0009 #include <perf/cpumap.h>
0010 #include <errno.h>
0011
0012 typedef void (*setup_probe_fn_t)(struct evsel *evsel);
0013
0014 static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str)
0015 {
0016 struct evlist *evlist;
0017 struct evsel *evsel;
0018 unsigned long flags = perf_event_open_cloexec_flag();
0019 int err = -EAGAIN, fd;
0020 static pid_t pid = -1;
0021
0022 evlist = evlist__new();
0023 if (!evlist)
0024 return -ENOMEM;
0025
0026 if (parse_event(evlist, str))
0027 goto out_delete;
0028
0029 evsel = evlist__first(evlist);
0030
0031 while (1) {
0032 fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
0033 if (fd < 0) {
0034 if (pid == -1 && errno == EACCES) {
0035 pid = 0;
0036 continue;
0037 }
0038 goto out_delete;
0039 }
0040 break;
0041 }
0042 close(fd);
0043
0044 fn(evsel);
0045
0046 fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags);
0047 if (fd < 0) {
0048 if (errno == EINVAL)
0049 err = -EINVAL;
0050 goto out_delete;
0051 }
0052 close(fd);
0053 err = 0;
0054
0055 out_delete:
0056 evlist__delete(evlist);
0057 return err;
0058 }
0059
0060 static bool perf_probe_api(setup_probe_fn_t fn)
0061 {
0062 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
0063 struct perf_cpu_map *cpus;
0064 struct perf_cpu cpu;
0065 int ret, i = 0;
0066
0067 cpus = perf_cpu_map__new(NULL);
0068 if (!cpus)
0069 return false;
0070 cpu = perf_cpu_map__cpu(cpus, 0);
0071 perf_cpu_map__put(cpus);
0072
0073 do {
0074 ret = perf_do_probe_api(fn, cpu, try[i++]);
0075 if (!ret)
0076 return true;
0077 } while (ret == -EAGAIN && try[i]);
0078
0079 return false;
0080 }
0081
0082 static void perf_probe_sample_identifier(struct evsel *evsel)
0083 {
0084 evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
0085 }
0086
0087 static void perf_probe_comm_exec(struct evsel *evsel)
0088 {
0089 evsel->core.attr.comm_exec = 1;
0090 }
0091
0092 static void perf_probe_context_switch(struct evsel *evsel)
0093 {
0094 evsel->core.attr.context_switch = 1;
0095 }
0096
0097 static void perf_probe_text_poke(struct evsel *evsel)
0098 {
0099 evsel->core.attr.text_poke = 1;
0100 }
0101
0102 static void perf_probe_build_id(struct evsel *evsel)
0103 {
0104 evsel->core.attr.build_id = 1;
0105 }
0106
0107 static void perf_probe_cgroup(struct evsel *evsel)
0108 {
0109 evsel->core.attr.cgroup = 1;
0110 }
0111
0112 bool perf_can_sample_identifier(void)
0113 {
0114 return perf_probe_api(perf_probe_sample_identifier);
0115 }
0116
0117 bool perf_can_comm_exec(void)
0118 {
0119 return perf_probe_api(perf_probe_comm_exec);
0120 }
0121
0122 bool perf_can_record_switch_events(void)
0123 {
0124 return perf_probe_api(perf_probe_context_switch);
0125 }
0126
0127 bool perf_can_record_text_poke_events(void)
0128 {
0129 return perf_probe_api(perf_probe_text_poke);
0130 }
0131
0132 bool perf_can_record_cpu_wide(void)
0133 {
0134 struct perf_event_attr attr = {
0135 .type = PERF_TYPE_SOFTWARE,
0136 .config = PERF_COUNT_SW_CPU_CLOCK,
0137 .exclude_kernel = 1,
0138 };
0139 struct perf_cpu_map *cpus;
0140 struct perf_cpu cpu;
0141 int fd;
0142
0143 cpus = perf_cpu_map__new(NULL);
0144 if (!cpus)
0145 return false;
0146
0147 cpu = perf_cpu_map__cpu(cpus, 0);
0148 perf_cpu_map__put(cpus);
0149
0150 fd = sys_perf_event_open(&attr, -1, cpu.cpu, -1, 0);
0151 if (fd < 0)
0152 return false;
0153 close(fd);
0154
0155 return true;
0156 }
0157
0158
0159
0160
0161
0162 bool perf_can_aux_sample(void)
0163 {
0164 struct perf_event_attr attr = {
0165 .size = sizeof(struct perf_event_attr),
0166 .exclude_kernel = 1,
0167
0168
0169
0170
0171 .aux_sample_size = 1,
0172 };
0173 int fd;
0174
0175 fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
0176
0177
0178
0179
0180
0181 if (fd < 0 && errno == E2BIG)
0182 return false;
0183 if (fd >= 0)
0184 close(fd);
0185
0186 return true;
0187 }
0188
0189 bool perf_can_record_build_id(void)
0190 {
0191 return perf_probe_api(perf_probe_build_id);
0192 }
0193
0194 bool perf_can_record_cgroup(void)
0195 {
0196 return perf_probe_api(perf_probe_cgroup);
0197 }