diff options
Diffstat (limited to 'tools/perf/util/record.c')
-rw-r--r-- | tools/perf/util/record.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c new file mode 100644 index 000000000000..18d73aa2f0f8 --- /dev/null +++ b/tools/perf/util/record.c | |||
@@ -0,0 +1,108 @@ | |||
1 | #include "evlist.h" | ||
2 | #include "evsel.h" | ||
3 | #include "cpumap.h" | ||
4 | #include "parse-events.h" | ||
5 | |||
6 | typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); | ||
7 | |||
8 | static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) | ||
9 | { | ||
10 | struct perf_evlist *evlist; | ||
11 | struct perf_evsel *evsel; | ||
12 | int err = -EAGAIN, fd; | ||
13 | |||
14 | evlist = perf_evlist__new(); | ||
15 | if (!evlist) | ||
16 | return -ENOMEM; | ||
17 | |||
18 | if (parse_events(evlist, str)) | ||
19 | goto out_delete; | ||
20 | |||
21 | evsel = perf_evlist__first(evlist); | ||
22 | |||
23 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); | ||
24 | if (fd < 0) | ||
25 | goto out_delete; | ||
26 | close(fd); | ||
27 | |||
28 | fn(evsel); | ||
29 | |||
30 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); | ||
31 | if (fd < 0) { | ||
32 | if (errno == EINVAL) | ||
33 | err = -EINVAL; | ||
34 | goto out_delete; | ||
35 | } | ||
36 | close(fd); | ||
37 | err = 0; | ||
38 | |||
39 | out_delete: | ||
40 | perf_evlist__delete(evlist); | ||
41 | return err; | ||
42 | } | ||
43 | |||
44 | static bool perf_probe_api(setup_probe_fn_t fn) | ||
45 | { | ||
46 | const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL}; | ||
47 | struct cpu_map *cpus; | ||
48 | int cpu, ret, i = 0; | ||
49 | |||
50 | cpus = cpu_map__new(NULL); | ||
51 | if (!cpus) | ||
52 | return false; | ||
53 | cpu = cpus->map[0]; | ||
54 | cpu_map__delete(cpus); | ||
55 | |||
56 | do { | ||
57 | ret = perf_do_probe_api(fn, cpu, try[i++]); | ||
58 | if (!ret) | ||
59 | return true; | ||
60 | } while (ret == -EAGAIN && try[i]); | ||
61 | |||
62 | return false; | ||
63 | } | ||
64 | |||
65 | static void perf_probe_sample_identifier(struct perf_evsel *evsel) | ||
66 | { | ||
67 | evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; | ||
68 | } | ||
69 | |||
70 | bool perf_can_sample_identifier(void) | ||
71 | { | ||
72 | return perf_probe_api(perf_probe_sample_identifier); | ||
73 | } | ||
74 | |||
75 | void perf_evlist__config(struct perf_evlist *evlist, | ||
76 | struct perf_record_opts *opts) | ||
77 | { | ||
78 | struct perf_evsel *evsel; | ||
79 | bool use_sample_identifier = false; | ||
80 | |||
81 | /* | ||
82 | * Set the evsel leader links before we configure attributes, | ||
83 | * since some might depend on this info. | ||
84 | */ | ||
85 | if (opts->group) | ||
86 | perf_evlist__set_leader(evlist); | ||
87 | |||
88 | if (evlist->cpus->map[0] < 0) | ||
89 | opts->no_inherit = true; | ||
90 | |||
91 | list_for_each_entry(evsel, &evlist->entries, node) | ||
92 | perf_evsel__config(evsel, opts); | ||
93 | |||
94 | if (evlist->nr_entries > 1) { | ||
95 | struct perf_evsel *first = perf_evlist__first(evlist); | ||
96 | |||
97 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
98 | if (evsel->attr.sample_type == first->attr.sample_type) | ||
99 | continue; | ||
100 | use_sample_identifier = perf_can_sample_identifier(); | ||
101 | break; | ||
102 | } | ||
103 | list_for_each_entry(evsel, &evlist->entries, node) | ||
104 | perf_evsel__set_sample_id(evsel, use_sample_identifier); | ||
105 | } | ||
106 | |||
107 | perf_evlist__set_id_pos(evlist); | ||
108 | } | ||