#include "evlist.h" #include "evsel.h" #include "cpumap.h" #include "parse-events.h" typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) { struct perf_evlist *evlist; struct perf_evsel *evsel; int err = -EAGAIN, fd; evlist = perf_evlist__new(); if (!evlist) return -ENOMEM; if (parse_events(evlist, str)) goto out_delete; evsel = perf_evlist__first(evlist); fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); if (fd < 0) goto out_delete; close(fd); fn(evsel); fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); if (fd < 0) { if (errno == EINVAL) err = -EINVAL; goto out_delete; } close(fd); err = 0; out_delete: perf_evlist__delete(evlist); return err; } static bool perf_probe_api(setup_probe_fn_t fn) { const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL}; struct cpu_map *cpus; int cpu, ret, i = 0; cpus = cpu_map__new(NULL); if (!cpus) return false; cpu = cpus->map[0]; cpu_map__delete(cpus); do { ret = perf_do_probe_api(fn, cpu, try[i++]); if (!ret) return true; } while (ret == -EAGAIN && try[i]); return false; } static void perf_probe_sample_identifier(struct perf_evsel *evsel) { evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; } bool perf_can_sample_identifier(void) { return perf_probe_api(perf_probe_sample_identifier); } void perf_evlist__config(struct perf_evlist *evlist, struct perf_record_opts *opts) { struct perf_evsel *evsel; bool use_sample_identifier = false; /* * Set the evsel leader links before we configure attributes, * since some might depend on this info. */ if (opts->group) perf_evlist__set_leader(evlist); if (evlist->cpus->map[0] < 0) opts->no_inherit = true; list_for_each_entry(evsel, &evlist->entries, node) perf_evsel__config(evsel, opts); if (evlist->nr_entries > 1) { struct perf_evsel *first = perf_evlist__first(evlist); list_for_each_entry(evsel, &evlist->entries, node) { if (evsel->attr.sample_type == first->attr.sample_type) continue; use_sample_identifier = perf_can_sample_identifier(); break; } list_for_each_entry(evsel, &evlist->entries, node) perf_evsel__set_sample_id(evsel, use_sample_identifier); } perf_evlist__set_id_pos(evlist); }