Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
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  * Architectures are expected to know if AUX area sampling is supported by the
0160  * hardware. Here we check for kernel support.
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          * Non-zero value causes the kernel to calculate the effective
0169          * attribute size up to that byte.
0170          */
0171         .aux_sample_size = 1,
0172     };
0173     int fd;
0174 
0175     fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
0176     /*
0177      * If the kernel attribute is big enough to contain aux_sample_size
0178      * then we assume that it is supported. We are relying on the kernel to
0179      * validate the attribute size before anything else that could be wrong.
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 }