Commit a3f698fe3082ff80a7f3b27c9b64b4b748c81f9d
1 parent
cb0b29e086
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
perf evsel: Adopt parse_sample method from perf_event
Since we need evsel->{attr.{sample_{id_all,type}},sample_size}, reducing the number of parameters tools have to pass. Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-wdtmgak0ihgsmw1brb54a8h4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Showing 5 changed files with 11 additions and 15 deletions Inline Diff
tools/perf/util/event.h
1 | #ifndef __PERF_RECORD_H | 1 | #ifndef __PERF_RECORD_H |
2 | #define __PERF_RECORD_H | 2 | #define __PERF_RECORD_H |
3 | 3 | ||
4 | #include <limits.h> | 4 | #include <limits.h> |
5 | #include <stdio.h> | 5 | #include <stdio.h> |
6 | 6 | ||
7 | #include "../perf.h" | 7 | #include "../perf.h" |
8 | #include "map.h" | 8 | #include "map.h" |
9 | 9 | ||
10 | /* | 10 | /* |
11 | * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * | 11 | * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * |
12 | */ | 12 | */ |
13 | struct ip_event { | 13 | struct ip_event { |
14 | struct perf_event_header header; | 14 | struct perf_event_header header; |
15 | u64 ip; | 15 | u64 ip; |
16 | u32 pid, tid; | 16 | u32 pid, tid; |
17 | unsigned char __more_data[]; | 17 | unsigned char __more_data[]; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | struct mmap_event { | 20 | struct mmap_event { |
21 | struct perf_event_header header; | 21 | struct perf_event_header header; |
22 | u32 pid, tid; | 22 | u32 pid, tid; |
23 | u64 start; | 23 | u64 start; |
24 | u64 len; | 24 | u64 len; |
25 | u64 pgoff; | 25 | u64 pgoff; |
26 | char filename[PATH_MAX]; | 26 | char filename[PATH_MAX]; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | struct comm_event { | 29 | struct comm_event { |
30 | struct perf_event_header header; | 30 | struct perf_event_header header; |
31 | u32 pid, tid; | 31 | u32 pid, tid; |
32 | char comm[16]; | 32 | char comm[16]; |
33 | }; | 33 | }; |
34 | 34 | ||
35 | struct fork_event { | 35 | struct fork_event { |
36 | struct perf_event_header header; | 36 | struct perf_event_header header; |
37 | u32 pid, ppid; | 37 | u32 pid, ppid; |
38 | u32 tid, ptid; | 38 | u32 tid, ptid; |
39 | u64 time; | 39 | u64 time; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | struct lost_event { | 42 | struct lost_event { |
43 | struct perf_event_header header; | 43 | struct perf_event_header header; |
44 | u64 id; | 44 | u64 id; |
45 | u64 lost; | 45 | u64 lost; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID | 49 | * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID |
50 | */ | 50 | */ |
51 | struct read_event { | 51 | struct read_event { |
52 | struct perf_event_header header; | 52 | struct perf_event_header header; |
53 | u32 pid, tid; | 53 | u32 pid, tid; |
54 | u64 value; | 54 | u64 value; |
55 | u64 time_enabled; | 55 | u64 time_enabled; |
56 | u64 time_running; | 56 | u64 time_running; |
57 | u64 id; | 57 | u64 id; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | 60 | ||
61 | #define PERF_SAMPLE_MASK \ | 61 | #define PERF_SAMPLE_MASK \ |
62 | (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ | 62 | (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ |
63 | PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ | 63 | PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ |
64 | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ | 64 | PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \ |
65 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) | 65 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) |
66 | 66 | ||
67 | struct sample_event { | 67 | struct sample_event { |
68 | struct perf_event_header header; | 68 | struct perf_event_header header; |
69 | u64 array[]; | 69 | u64 array[]; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | struct perf_sample { | 72 | struct perf_sample { |
73 | u64 ip; | 73 | u64 ip; |
74 | u32 pid, tid; | 74 | u32 pid, tid; |
75 | u64 time; | 75 | u64 time; |
76 | u64 addr; | 76 | u64 addr; |
77 | u64 id; | 77 | u64 id; |
78 | u64 stream_id; | 78 | u64 stream_id; |
79 | u64 period; | 79 | u64 period; |
80 | u32 cpu; | 80 | u32 cpu; |
81 | u32 raw_size; | 81 | u32 raw_size; |
82 | void *raw_data; | 82 | void *raw_data; |
83 | struct ip_callchain *callchain; | 83 | struct ip_callchain *callchain; |
84 | struct branch_stack *branch_stack; | 84 | struct branch_stack *branch_stack; |
85 | }; | 85 | }; |
86 | 86 | ||
87 | #define BUILD_ID_SIZE 20 | 87 | #define BUILD_ID_SIZE 20 |
88 | 88 | ||
89 | struct build_id_event { | 89 | struct build_id_event { |
90 | struct perf_event_header header; | 90 | struct perf_event_header header; |
91 | pid_t pid; | 91 | pid_t pid; |
92 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | 92 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; |
93 | char filename[]; | 93 | char filename[]; |
94 | }; | 94 | }; |
95 | 95 | ||
96 | enum perf_user_event_type { /* above any possible kernel type */ | 96 | enum perf_user_event_type { /* above any possible kernel type */ |
97 | PERF_RECORD_USER_TYPE_START = 64, | 97 | PERF_RECORD_USER_TYPE_START = 64, |
98 | PERF_RECORD_HEADER_ATTR = 64, | 98 | PERF_RECORD_HEADER_ATTR = 64, |
99 | PERF_RECORD_HEADER_EVENT_TYPE = 65, | 99 | PERF_RECORD_HEADER_EVENT_TYPE = 65, |
100 | PERF_RECORD_HEADER_TRACING_DATA = 66, | 100 | PERF_RECORD_HEADER_TRACING_DATA = 66, |
101 | PERF_RECORD_HEADER_BUILD_ID = 67, | 101 | PERF_RECORD_HEADER_BUILD_ID = 67, |
102 | PERF_RECORD_FINISHED_ROUND = 68, | 102 | PERF_RECORD_FINISHED_ROUND = 68, |
103 | PERF_RECORD_HEADER_MAX | 103 | PERF_RECORD_HEADER_MAX |
104 | }; | 104 | }; |
105 | 105 | ||
106 | struct attr_event { | 106 | struct attr_event { |
107 | struct perf_event_header header; | 107 | struct perf_event_header header; |
108 | struct perf_event_attr attr; | 108 | struct perf_event_attr attr; |
109 | u64 id[]; | 109 | u64 id[]; |
110 | }; | 110 | }; |
111 | 111 | ||
112 | #define MAX_EVENT_NAME 64 | 112 | #define MAX_EVENT_NAME 64 |
113 | 113 | ||
114 | struct perf_trace_event_type { | 114 | struct perf_trace_event_type { |
115 | u64 event_id; | 115 | u64 event_id; |
116 | char name[MAX_EVENT_NAME]; | 116 | char name[MAX_EVENT_NAME]; |
117 | }; | 117 | }; |
118 | 118 | ||
119 | struct event_type_event { | 119 | struct event_type_event { |
120 | struct perf_event_header header; | 120 | struct perf_event_header header; |
121 | struct perf_trace_event_type event_type; | 121 | struct perf_trace_event_type event_type; |
122 | }; | 122 | }; |
123 | 123 | ||
124 | struct tracing_data_event { | 124 | struct tracing_data_event { |
125 | struct perf_event_header header; | 125 | struct perf_event_header header; |
126 | u32 size; | 126 | u32 size; |
127 | }; | 127 | }; |
128 | 128 | ||
129 | union perf_event { | 129 | union perf_event { |
130 | struct perf_event_header header; | 130 | struct perf_event_header header; |
131 | struct ip_event ip; | 131 | struct ip_event ip; |
132 | struct mmap_event mmap; | 132 | struct mmap_event mmap; |
133 | struct comm_event comm; | 133 | struct comm_event comm; |
134 | struct fork_event fork; | 134 | struct fork_event fork; |
135 | struct lost_event lost; | 135 | struct lost_event lost; |
136 | struct read_event read; | 136 | struct read_event read; |
137 | struct sample_event sample; | 137 | struct sample_event sample; |
138 | struct attr_event attr; | 138 | struct attr_event attr; |
139 | struct event_type_event event_type; | 139 | struct event_type_event event_type; |
140 | struct tracing_data_event tracing_data; | 140 | struct tracing_data_event tracing_data; |
141 | struct build_id_event build_id; | 141 | struct build_id_event build_id; |
142 | }; | 142 | }; |
143 | 143 | ||
144 | void perf_event__print_totals(void); | 144 | void perf_event__print_totals(void); |
145 | 145 | ||
146 | struct perf_tool; | 146 | struct perf_tool; |
147 | struct thread_map; | 147 | struct thread_map; |
148 | 148 | ||
149 | typedef int (*perf_event__handler_t)(struct perf_tool *tool, | 149 | typedef int (*perf_event__handler_t)(struct perf_tool *tool, |
150 | union perf_event *event, | 150 | union perf_event *event, |
151 | struct perf_sample *sample, | 151 | struct perf_sample *sample, |
152 | struct machine *machine); | 152 | struct machine *machine); |
153 | 153 | ||
154 | int perf_event__synthesize_thread_map(struct perf_tool *tool, | 154 | int perf_event__synthesize_thread_map(struct perf_tool *tool, |
155 | struct thread_map *threads, | 155 | struct thread_map *threads, |
156 | perf_event__handler_t process, | 156 | perf_event__handler_t process, |
157 | struct machine *machine); | 157 | struct machine *machine); |
158 | int perf_event__synthesize_threads(struct perf_tool *tool, | 158 | int perf_event__synthesize_threads(struct perf_tool *tool, |
159 | perf_event__handler_t process, | 159 | perf_event__handler_t process, |
160 | struct machine *machine); | 160 | struct machine *machine); |
161 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 161 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, |
162 | perf_event__handler_t process, | 162 | perf_event__handler_t process, |
163 | struct machine *machine, | 163 | struct machine *machine, |
164 | const char *symbol_name); | 164 | const char *symbol_name); |
165 | 165 | ||
166 | int perf_event__synthesize_modules(struct perf_tool *tool, | 166 | int perf_event__synthesize_modules(struct perf_tool *tool, |
167 | perf_event__handler_t process, | 167 | perf_event__handler_t process, |
168 | struct machine *machine); | 168 | struct machine *machine); |
169 | 169 | ||
170 | int perf_event__process_comm(struct perf_tool *tool, | 170 | int perf_event__process_comm(struct perf_tool *tool, |
171 | union perf_event *event, | 171 | union perf_event *event, |
172 | struct perf_sample *sample, | 172 | struct perf_sample *sample, |
173 | struct machine *machine); | 173 | struct machine *machine); |
174 | int perf_event__process_lost(struct perf_tool *tool, | 174 | int perf_event__process_lost(struct perf_tool *tool, |
175 | union perf_event *event, | 175 | union perf_event *event, |
176 | struct perf_sample *sample, | 176 | struct perf_sample *sample, |
177 | struct machine *machine); | 177 | struct machine *machine); |
178 | int perf_event__process_mmap(struct perf_tool *tool, | 178 | int perf_event__process_mmap(struct perf_tool *tool, |
179 | union perf_event *event, | 179 | union perf_event *event, |
180 | struct perf_sample *sample, | 180 | struct perf_sample *sample, |
181 | struct machine *machine); | 181 | struct machine *machine); |
182 | int perf_event__process_task(struct perf_tool *tool, | 182 | int perf_event__process_task(struct perf_tool *tool, |
183 | union perf_event *event, | 183 | union perf_event *event, |
184 | struct perf_sample *sample, | 184 | struct perf_sample *sample, |
185 | struct machine *machine); | 185 | struct machine *machine); |
186 | int perf_event__process(struct perf_tool *tool, | 186 | int perf_event__process(struct perf_tool *tool, |
187 | union perf_event *event, | 187 | union perf_event *event, |
188 | struct perf_sample *sample, | 188 | struct perf_sample *sample, |
189 | struct machine *machine); | 189 | struct machine *machine); |
190 | 190 | ||
191 | struct addr_location; | 191 | struct addr_location; |
192 | int perf_event__preprocess_sample(const union perf_event *self, | 192 | int perf_event__preprocess_sample(const union perf_event *self, |
193 | struct machine *machine, | 193 | struct machine *machine, |
194 | struct addr_location *al, | 194 | struct addr_location *al, |
195 | struct perf_sample *sample, | 195 | struct perf_sample *sample, |
196 | symbol_filter_t filter); | 196 | symbol_filter_t filter); |
197 | 197 | ||
198 | const char *perf_event__name(unsigned int id); | 198 | const char *perf_event__name(unsigned int id); |
199 | 199 | ||
200 | int perf_event__parse_sample(const union perf_event *event, u64 type, | ||
201 | int sample_size, bool sample_id_all, | ||
202 | struct perf_sample *sample, bool swapped); | ||
203 | int perf_event__synthesize_sample(union perf_event *event, u64 type, | 200 | int perf_event__synthesize_sample(union perf_event *event, u64 type, |
204 | const struct perf_sample *sample, | 201 | const struct perf_sample *sample, |
205 | bool swapped); | 202 | bool swapped); |
206 | 203 | ||
207 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); | 204 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); |
208 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); | 205 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); |
209 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); | 206 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); |
210 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); | 207 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); |
211 | 208 | ||
212 | #endif /* __PERF_RECORD_H */ | 209 | #endif /* __PERF_RECORD_H */ |
213 | 210 |
tools/perf/util/evlist.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
3 | * | 3 | * |
4 | * Parts came from builtin-{top,stat,record}.c, see those files for further | 4 | * Parts came from builtin-{top,stat,record}.c, see those files for further |
5 | * copyright notes. | 5 | * copyright notes. |
6 | * | 6 | * |
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | #include "util.h" | 9 | #include "util.h" |
10 | #include "debugfs.h" | 10 | #include "debugfs.h" |
11 | #include <poll.h> | 11 | #include <poll.h> |
12 | #include "cpumap.h" | 12 | #include "cpumap.h" |
13 | #include "thread_map.h" | 13 | #include "thread_map.h" |
14 | #include "target.h" | 14 | #include "target.h" |
15 | #include "evlist.h" | 15 | #include "evlist.h" |
16 | #include "evsel.h" | 16 | #include "evsel.h" |
17 | #include <unistd.h> | 17 | #include <unistd.h> |
18 | 18 | ||
19 | #include "parse-events.h" | 19 | #include "parse-events.h" |
20 | 20 | ||
21 | #include <sys/mman.h> | 21 | #include <sys/mman.h> |
22 | 22 | ||
23 | #include <linux/bitops.h> | 23 | #include <linux/bitops.h> |
24 | #include <linux/hash.h> | 24 | #include <linux/hash.h> |
25 | 25 | ||
26 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 26 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
27 | #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) | 27 | #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) |
28 | 28 | ||
29 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | 29 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, |
30 | struct thread_map *threads) | 30 | struct thread_map *threads) |
31 | { | 31 | { |
32 | int i; | 32 | int i; |
33 | 33 | ||
34 | for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) | 34 | for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) |
35 | INIT_HLIST_HEAD(&evlist->heads[i]); | 35 | INIT_HLIST_HEAD(&evlist->heads[i]); |
36 | INIT_LIST_HEAD(&evlist->entries); | 36 | INIT_LIST_HEAD(&evlist->entries); |
37 | perf_evlist__set_maps(evlist, cpus, threads); | 37 | perf_evlist__set_maps(evlist, cpus, threads); |
38 | evlist->workload.pid = -1; | 38 | evlist->workload.pid = -1; |
39 | } | 39 | } |
40 | 40 | ||
41 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 41 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, |
42 | struct thread_map *threads) | 42 | struct thread_map *threads) |
43 | { | 43 | { |
44 | struct perf_evlist *evlist = zalloc(sizeof(*evlist)); | 44 | struct perf_evlist *evlist = zalloc(sizeof(*evlist)); |
45 | 45 | ||
46 | if (evlist != NULL) | 46 | if (evlist != NULL) |
47 | perf_evlist__init(evlist, cpus, threads); | 47 | perf_evlist__init(evlist, cpus, threads); |
48 | 48 | ||
49 | return evlist; | 49 | return evlist; |
50 | } | 50 | } |
51 | 51 | ||
52 | void perf_evlist__config_attrs(struct perf_evlist *evlist, | 52 | void perf_evlist__config_attrs(struct perf_evlist *evlist, |
53 | struct perf_record_opts *opts) | 53 | struct perf_record_opts *opts) |
54 | { | 54 | { |
55 | struct perf_evsel *evsel, *first; | 55 | struct perf_evsel *evsel, *first; |
56 | 56 | ||
57 | if (evlist->cpus->map[0] < 0) | 57 | if (evlist->cpus->map[0] < 0) |
58 | opts->no_inherit = true; | 58 | opts->no_inherit = true; |
59 | 59 | ||
60 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 60 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
61 | 61 | ||
62 | list_for_each_entry(evsel, &evlist->entries, node) { | 62 | list_for_each_entry(evsel, &evlist->entries, node) { |
63 | perf_evsel__config(evsel, opts, first); | 63 | perf_evsel__config(evsel, opts, first); |
64 | 64 | ||
65 | if (evlist->nr_entries > 1) | 65 | if (evlist->nr_entries > 1) |
66 | evsel->attr.sample_type |= PERF_SAMPLE_ID; | 66 | evsel->attr.sample_type |= PERF_SAMPLE_ID; |
67 | } | 67 | } |
68 | } | 68 | } |
69 | 69 | ||
70 | static void perf_evlist__purge(struct perf_evlist *evlist) | 70 | static void perf_evlist__purge(struct perf_evlist *evlist) |
71 | { | 71 | { |
72 | struct perf_evsel *pos, *n; | 72 | struct perf_evsel *pos, *n; |
73 | 73 | ||
74 | list_for_each_entry_safe(pos, n, &evlist->entries, node) { | 74 | list_for_each_entry_safe(pos, n, &evlist->entries, node) { |
75 | list_del_init(&pos->node); | 75 | list_del_init(&pos->node); |
76 | perf_evsel__delete(pos); | 76 | perf_evsel__delete(pos); |
77 | } | 77 | } |
78 | 78 | ||
79 | evlist->nr_entries = 0; | 79 | evlist->nr_entries = 0; |
80 | } | 80 | } |
81 | 81 | ||
82 | void perf_evlist__exit(struct perf_evlist *evlist) | 82 | void perf_evlist__exit(struct perf_evlist *evlist) |
83 | { | 83 | { |
84 | free(evlist->mmap); | 84 | free(evlist->mmap); |
85 | free(evlist->pollfd); | 85 | free(evlist->pollfd); |
86 | evlist->mmap = NULL; | 86 | evlist->mmap = NULL; |
87 | evlist->pollfd = NULL; | 87 | evlist->pollfd = NULL; |
88 | } | 88 | } |
89 | 89 | ||
90 | void perf_evlist__delete(struct perf_evlist *evlist) | 90 | void perf_evlist__delete(struct perf_evlist *evlist) |
91 | { | 91 | { |
92 | perf_evlist__purge(evlist); | 92 | perf_evlist__purge(evlist); |
93 | perf_evlist__exit(evlist); | 93 | perf_evlist__exit(evlist); |
94 | free(evlist); | 94 | free(evlist); |
95 | } | 95 | } |
96 | 96 | ||
97 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) | 97 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) |
98 | { | 98 | { |
99 | list_add_tail(&entry->node, &evlist->entries); | 99 | list_add_tail(&entry->node, &evlist->entries); |
100 | ++evlist->nr_entries; | 100 | ++evlist->nr_entries; |
101 | } | 101 | } |
102 | 102 | ||
103 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, | 103 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, |
104 | struct list_head *list, | 104 | struct list_head *list, |
105 | int nr_entries) | 105 | int nr_entries) |
106 | { | 106 | { |
107 | list_splice_tail(list, &evlist->entries); | 107 | list_splice_tail(list, &evlist->entries); |
108 | evlist->nr_entries += nr_entries; | 108 | evlist->nr_entries += nr_entries; |
109 | } | 109 | } |
110 | 110 | ||
111 | int perf_evlist__add_default(struct perf_evlist *evlist) | 111 | int perf_evlist__add_default(struct perf_evlist *evlist) |
112 | { | 112 | { |
113 | struct perf_event_attr attr = { | 113 | struct perf_event_attr attr = { |
114 | .type = PERF_TYPE_HARDWARE, | 114 | .type = PERF_TYPE_HARDWARE, |
115 | .config = PERF_COUNT_HW_CPU_CYCLES, | 115 | .config = PERF_COUNT_HW_CPU_CYCLES, |
116 | }; | 116 | }; |
117 | struct perf_evsel *evsel; | 117 | struct perf_evsel *evsel; |
118 | 118 | ||
119 | event_attr_init(&attr); | 119 | event_attr_init(&attr); |
120 | 120 | ||
121 | evsel = perf_evsel__new(&attr, 0); | 121 | evsel = perf_evsel__new(&attr, 0); |
122 | if (evsel == NULL) | 122 | if (evsel == NULL) |
123 | goto error; | 123 | goto error; |
124 | 124 | ||
125 | /* use strdup() because free(evsel) assumes name is allocated */ | 125 | /* use strdup() because free(evsel) assumes name is allocated */ |
126 | evsel->name = strdup("cycles"); | 126 | evsel->name = strdup("cycles"); |
127 | if (!evsel->name) | 127 | if (!evsel->name) |
128 | goto error_free; | 128 | goto error_free; |
129 | 129 | ||
130 | perf_evlist__add(evlist, evsel); | 130 | perf_evlist__add(evlist, evsel); |
131 | return 0; | 131 | return 0; |
132 | error_free: | 132 | error_free: |
133 | perf_evsel__delete(evsel); | 133 | perf_evsel__delete(evsel); |
134 | error: | 134 | error: |
135 | return -ENOMEM; | 135 | return -ENOMEM; |
136 | } | 136 | } |
137 | 137 | ||
138 | int perf_evlist__add_attrs(struct perf_evlist *evlist, | 138 | int perf_evlist__add_attrs(struct perf_evlist *evlist, |
139 | struct perf_event_attr *attrs, size_t nr_attrs) | 139 | struct perf_event_attr *attrs, size_t nr_attrs) |
140 | { | 140 | { |
141 | struct perf_evsel *evsel, *n; | 141 | struct perf_evsel *evsel, *n; |
142 | LIST_HEAD(head); | 142 | LIST_HEAD(head); |
143 | size_t i; | 143 | size_t i; |
144 | 144 | ||
145 | for (i = 0; i < nr_attrs; i++) { | 145 | for (i = 0; i < nr_attrs; i++) { |
146 | evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i); | 146 | evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i); |
147 | if (evsel == NULL) | 147 | if (evsel == NULL) |
148 | goto out_delete_partial_list; | 148 | goto out_delete_partial_list; |
149 | list_add_tail(&evsel->node, &head); | 149 | list_add_tail(&evsel->node, &head); |
150 | } | 150 | } |
151 | 151 | ||
152 | perf_evlist__splice_list_tail(evlist, &head, nr_attrs); | 152 | perf_evlist__splice_list_tail(evlist, &head, nr_attrs); |
153 | 153 | ||
154 | return 0; | 154 | return 0; |
155 | 155 | ||
156 | out_delete_partial_list: | 156 | out_delete_partial_list: |
157 | list_for_each_entry_safe(evsel, n, &head, node) | 157 | list_for_each_entry_safe(evsel, n, &head, node) |
158 | perf_evsel__delete(evsel); | 158 | perf_evsel__delete(evsel); |
159 | return -1; | 159 | return -1; |
160 | } | 160 | } |
161 | 161 | ||
162 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | 162 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, |
163 | struct perf_event_attr *attrs, size_t nr_attrs) | 163 | struct perf_event_attr *attrs, size_t nr_attrs) |
164 | { | 164 | { |
165 | size_t i; | 165 | size_t i; |
166 | 166 | ||
167 | for (i = 0; i < nr_attrs; i++) | 167 | for (i = 0; i < nr_attrs; i++) |
168 | event_attr_init(attrs + i); | 168 | event_attr_init(attrs + i); |
169 | 169 | ||
170 | return perf_evlist__add_attrs(evlist, attrs, nr_attrs); | 170 | return perf_evlist__add_attrs(evlist, attrs, nr_attrs); |
171 | } | 171 | } |
172 | 172 | ||
173 | static int trace_event__id(const char *evname) | 173 | static int trace_event__id(const char *evname) |
174 | { | 174 | { |
175 | char *filename, *colon; | 175 | char *filename, *colon; |
176 | int err = -1, fd; | 176 | int err = -1, fd; |
177 | 177 | ||
178 | if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0) | 178 | if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0) |
179 | return -1; | 179 | return -1; |
180 | 180 | ||
181 | colon = strrchr(filename, ':'); | 181 | colon = strrchr(filename, ':'); |
182 | if (colon != NULL) | 182 | if (colon != NULL) |
183 | *colon = '/'; | 183 | *colon = '/'; |
184 | 184 | ||
185 | fd = open(filename, O_RDONLY); | 185 | fd = open(filename, O_RDONLY); |
186 | if (fd >= 0) { | 186 | if (fd >= 0) { |
187 | char id[16]; | 187 | char id[16]; |
188 | if (read(fd, id, sizeof(id)) > 0) | 188 | if (read(fd, id, sizeof(id)) > 0) |
189 | err = atoi(id); | 189 | err = atoi(id); |
190 | close(fd); | 190 | close(fd); |
191 | } | 191 | } |
192 | 192 | ||
193 | free(filename); | 193 | free(filename); |
194 | return err; | 194 | return err; |
195 | } | 195 | } |
196 | 196 | ||
197 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | 197 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, |
198 | const char *tracepoints[], | 198 | const char *tracepoints[], |
199 | size_t nr_tracepoints) | 199 | size_t nr_tracepoints) |
200 | { | 200 | { |
201 | int err; | 201 | int err; |
202 | size_t i; | 202 | size_t i; |
203 | struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs)); | 203 | struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs)); |
204 | 204 | ||
205 | if (attrs == NULL) | 205 | if (attrs == NULL) |
206 | return -1; | 206 | return -1; |
207 | 207 | ||
208 | for (i = 0; i < nr_tracepoints; i++) { | 208 | for (i = 0; i < nr_tracepoints; i++) { |
209 | err = trace_event__id(tracepoints[i]); | 209 | err = trace_event__id(tracepoints[i]); |
210 | 210 | ||
211 | if (err < 0) | 211 | if (err < 0) |
212 | goto out_free_attrs; | 212 | goto out_free_attrs; |
213 | 213 | ||
214 | attrs[i].type = PERF_TYPE_TRACEPOINT; | 214 | attrs[i].type = PERF_TYPE_TRACEPOINT; |
215 | attrs[i].config = err; | 215 | attrs[i].config = err; |
216 | attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | | 216 | attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | |
217 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD); | 217 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD); |
218 | attrs[i].sample_period = 1; | 218 | attrs[i].sample_period = 1; |
219 | } | 219 | } |
220 | 220 | ||
221 | err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints); | 221 | err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints); |
222 | out_free_attrs: | 222 | out_free_attrs: |
223 | free(attrs); | 223 | free(attrs); |
224 | return err; | 224 | return err; |
225 | } | 225 | } |
226 | 226 | ||
227 | struct perf_evsel * | 227 | struct perf_evsel * |
228 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | 228 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) |
229 | { | 229 | { |
230 | struct perf_evsel *evsel; | 230 | struct perf_evsel *evsel; |
231 | 231 | ||
232 | list_for_each_entry(evsel, &evlist->entries, node) { | 232 | list_for_each_entry(evsel, &evlist->entries, node) { |
233 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | 233 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && |
234 | (int)evsel->attr.config == id) | 234 | (int)evsel->attr.config == id) |
235 | return evsel; | 235 | return evsel; |
236 | } | 236 | } |
237 | 237 | ||
238 | return NULL; | 238 | return NULL; |
239 | } | 239 | } |
240 | 240 | ||
241 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | 241 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, |
242 | const struct perf_evsel_str_handler *assocs, | 242 | const struct perf_evsel_str_handler *assocs, |
243 | size_t nr_assocs) | 243 | size_t nr_assocs) |
244 | { | 244 | { |
245 | struct perf_evsel *evsel; | 245 | struct perf_evsel *evsel; |
246 | int err; | 246 | int err; |
247 | size_t i; | 247 | size_t i; |
248 | 248 | ||
249 | for (i = 0; i < nr_assocs; i++) { | 249 | for (i = 0; i < nr_assocs; i++) { |
250 | err = trace_event__id(assocs[i].name); | 250 | err = trace_event__id(assocs[i].name); |
251 | if (err < 0) | 251 | if (err < 0) |
252 | goto out; | 252 | goto out; |
253 | 253 | ||
254 | evsel = perf_evlist__find_tracepoint_by_id(evlist, err); | 254 | evsel = perf_evlist__find_tracepoint_by_id(evlist, err); |
255 | if (evsel == NULL) | 255 | if (evsel == NULL) |
256 | continue; | 256 | continue; |
257 | 257 | ||
258 | err = -EEXIST; | 258 | err = -EEXIST; |
259 | if (evsel->handler.func != NULL) | 259 | if (evsel->handler.func != NULL) |
260 | goto out; | 260 | goto out; |
261 | evsel->handler.func = assocs[i].handler; | 261 | evsel->handler.func = assocs[i].handler; |
262 | } | 262 | } |
263 | 263 | ||
264 | err = 0; | 264 | err = 0; |
265 | out: | 265 | out: |
266 | return err; | 266 | return err; |
267 | } | 267 | } |
268 | 268 | ||
269 | void perf_evlist__disable(struct perf_evlist *evlist) | 269 | void perf_evlist__disable(struct perf_evlist *evlist) |
270 | { | 270 | { |
271 | int cpu, thread; | 271 | int cpu, thread; |
272 | struct perf_evsel *pos; | 272 | struct perf_evsel *pos; |
273 | 273 | ||
274 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 274 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { |
275 | list_for_each_entry(pos, &evlist->entries, node) { | 275 | list_for_each_entry(pos, &evlist->entries, node) { |
276 | for (thread = 0; thread < evlist->threads->nr; thread++) | 276 | for (thread = 0; thread < evlist->threads->nr; thread++) |
277 | ioctl(FD(pos, cpu, thread), | 277 | ioctl(FD(pos, cpu, thread), |
278 | PERF_EVENT_IOC_DISABLE, 0); | 278 | PERF_EVENT_IOC_DISABLE, 0); |
279 | } | 279 | } |
280 | } | 280 | } |
281 | } | 281 | } |
282 | 282 | ||
283 | void perf_evlist__enable(struct perf_evlist *evlist) | 283 | void perf_evlist__enable(struct perf_evlist *evlist) |
284 | { | 284 | { |
285 | int cpu, thread; | 285 | int cpu, thread; |
286 | struct perf_evsel *pos; | 286 | struct perf_evsel *pos; |
287 | 287 | ||
288 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 288 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { |
289 | list_for_each_entry(pos, &evlist->entries, node) { | 289 | list_for_each_entry(pos, &evlist->entries, node) { |
290 | for (thread = 0; thread < evlist->threads->nr; thread++) | 290 | for (thread = 0; thread < evlist->threads->nr; thread++) |
291 | ioctl(FD(pos, cpu, thread), | 291 | ioctl(FD(pos, cpu, thread), |
292 | PERF_EVENT_IOC_ENABLE, 0); | 292 | PERF_EVENT_IOC_ENABLE, 0); |
293 | } | 293 | } |
294 | } | 294 | } |
295 | } | 295 | } |
296 | 296 | ||
297 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 297 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
298 | { | 298 | { |
299 | int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; | 299 | int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; |
300 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); | 300 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); |
301 | return evlist->pollfd != NULL ? 0 : -ENOMEM; | 301 | return evlist->pollfd != NULL ? 0 : -ENOMEM; |
302 | } | 302 | } |
303 | 303 | ||
304 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) | 304 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) |
305 | { | 305 | { |
306 | fcntl(fd, F_SETFL, O_NONBLOCK); | 306 | fcntl(fd, F_SETFL, O_NONBLOCK); |
307 | evlist->pollfd[evlist->nr_fds].fd = fd; | 307 | evlist->pollfd[evlist->nr_fds].fd = fd; |
308 | evlist->pollfd[evlist->nr_fds].events = POLLIN; | 308 | evlist->pollfd[evlist->nr_fds].events = POLLIN; |
309 | evlist->nr_fds++; | 309 | evlist->nr_fds++; |
310 | } | 310 | } |
311 | 311 | ||
312 | static void perf_evlist__id_hash(struct perf_evlist *evlist, | 312 | static void perf_evlist__id_hash(struct perf_evlist *evlist, |
313 | struct perf_evsel *evsel, | 313 | struct perf_evsel *evsel, |
314 | int cpu, int thread, u64 id) | 314 | int cpu, int thread, u64 id) |
315 | { | 315 | { |
316 | int hash; | 316 | int hash; |
317 | struct perf_sample_id *sid = SID(evsel, cpu, thread); | 317 | struct perf_sample_id *sid = SID(evsel, cpu, thread); |
318 | 318 | ||
319 | sid->id = id; | 319 | sid->id = id; |
320 | sid->evsel = evsel; | 320 | sid->evsel = evsel; |
321 | hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); | 321 | hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); |
322 | hlist_add_head(&sid->node, &evlist->heads[hash]); | 322 | hlist_add_head(&sid->node, &evlist->heads[hash]); |
323 | } | 323 | } |
324 | 324 | ||
325 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, | 325 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, |
326 | int cpu, int thread, u64 id) | 326 | int cpu, int thread, u64 id) |
327 | { | 327 | { |
328 | perf_evlist__id_hash(evlist, evsel, cpu, thread, id); | 328 | perf_evlist__id_hash(evlist, evsel, cpu, thread, id); |
329 | evsel->id[evsel->ids++] = id; | 329 | evsel->id[evsel->ids++] = id; |
330 | } | 330 | } |
331 | 331 | ||
332 | static int perf_evlist__id_add_fd(struct perf_evlist *evlist, | 332 | static int perf_evlist__id_add_fd(struct perf_evlist *evlist, |
333 | struct perf_evsel *evsel, | 333 | struct perf_evsel *evsel, |
334 | int cpu, int thread, int fd) | 334 | int cpu, int thread, int fd) |
335 | { | 335 | { |
336 | u64 read_data[4] = { 0, }; | 336 | u64 read_data[4] = { 0, }; |
337 | int id_idx = 1; /* The first entry is the counter value */ | 337 | int id_idx = 1; /* The first entry is the counter value */ |
338 | 338 | ||
339 | if (!(evsel->attr.read_format & PERF_FORMAT_ID) || | 339 | if (!(evsel->attr.read_format & PERF_FORMAT_ID) || |
340 | read(fd, &read_data, sizeof(read_data)) == -1) | 340 | read(fd, &read_data, sizeof(read_data)) == -1) |
341 | return -1; | 341 | return -1; |
342 | 342 | ||
343 | if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) | 343 | if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) |
344 | ++id_idx; | 344 | ++id_idx; |
345 | if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) | 345 | if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) |
346 | ++id_idx; | 346 | ++id_idx; |
347 | 347 | ||
348 | perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]); | 348 | perf_evlist__id_add(evlist, evsel, cpu, thread, read_data[id_idx]); |
349 | return 0; | 349 | return 0; |
350 | } | 350 | } |
351 | 351 | ||
352 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) | 352 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) |
353 | { | 353 | { |
354 | struct hlist_head *head; | 354 | struct hlist_head *head; |
355 | struct hlist_node *pos; | 355 | struct hlist_node *pos; |
356 | struct perf_sample_id *sid; | 356 | struct perf_sample_id *sid; |
357 | int hash; | 357 | int hash; |
358 | 358 | ||
359 | if (evlist->nr_entries == 1) | 359 | if (evlist->nr_entries == 1) |
360 | return list_entry(evlist->entries.next, struct perf_evsel, node); | 360 | return list_entry(evlist->entries.next, struct perf_evsel, node); |
361 | 361 | ||
362 | hash = hash_64(id, PERF_EVLIST__HLIST_BITS); | 362 | hash = hash_64(id, PERF_EVLIST__HLIST_BITS); |
363 | head = &evlist->heads[hash]; | 363 | head = &evlist->heads[hash]; |
364 | 364 | ||
365 | hlist_for_each_entry(sid, pos, head, node) | 365 | hlist_for_each_entry(sid, pos, head, node) |
366 | if (sid->id == id) | 366 | if (sid->id == id) |
367 | return sid->evsel; | 367 | return sid->evsel; |
368 | 368 | ||
369 | if (!perf_evlist__sample_id_all(evlist)) | 369 | if (!perf_evlist__sample_id_all(evlist)) |
370 | return list_entry(evlist->entries.next, struct perf_evsel, node); | 370 | return list_entry(evlist->entries.next, struct perf_evsel, node); |
371 | 371 | ||
372 | return NULL; | 372 | return NULL; |
373 | } | 373 | } |
374 | 374 | ||
375 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | 375 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) |
376 | { | 376 | { |
377 | /* XXX Move this to perf.c, making it generally available */ | 377 | /* XXX Move this to perf.c, making it generally available */ |
378 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); | 378 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); |
379 | struct perf_mmap *md = &evlist->mmap[idx]; | 379 | struct perf_mmap *md = &evlist->mmap[idx]; |
380 | unsigned int head = perf_mmap__read_head(md); | 380 | unsigned int head = perf_mmap__read_head(md); |
381 | unsigned int old = md->prev; | 381 | unsigned int old = md->prev; |
382 | unsigned char *data = md->base + page_size; | 382 | unsigned char *data = md->base + page_size; |
383 | union perf_event *event = NULL; | 383 | union perf_event *event = NULL; |
384 | 384 | ||
385 | if (evlist->overwrite) { | 385 | if (evlist->overwrite) { |
386 | /* | 386 | /* |
387 | * If we're further behind than half the buffer, there's a chance | 387 | * If we're further behind than half the buffer, there's a chance |
388 | * the writer will bite our tail and mess up the samples under us. | 388 | * the writer will bite our tail and mess up the samples under us. |
389 | * | 389 | * |
390 | * If we somehow ended up ahead of the head, we got messed up. | 390 | * If we somehow ended up ahead of the head, we got messed up. |
391 | * | 391 | * |
392 | * In either case, truncate and restart at head. | 392 | * In either case, truncate and restart at head. |
393 | */ | 393 | */ |
394 | int diff = head - old; | 394 | int diff = head - old; |
395 | if (diff > md->mask / 2 || diff < 0) { | 395 | if (diff > md->mask / 2 || diff < 0) { |
396 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); | 396 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); |
397 | 397 | ||
398 | /* | 398 | /* |
399 | * head points to a known good entry, start there. | 399 | * head points to a known good entry, start there. |
400 | */ | 400 | */ |
401 | old = head; | 401 | old = head; |
402 | } | 402 | } |
403 | } | 403 | } |
404 | 404 | ||
405 | if (old != head) { | 405 | if (old != head) { |
406 | size_t size; | 406 | size_t size; |
407 | 407 | ||
408 | event = (union perf_event *)&data[old & md->mask]; | 408 | event = (union perf_event *)&data[old & md->mask]; |
409 | size = event->header.size; | 409 | size = event->header.size; |
410 | 410 | ||
411 | /* | 411 | /* |
412 | * Event straddles the mmap boundary -- header should always | 412 | * Event straddles the mmap boundary -- header should always |
413 | * be inside due to u64 alignment of output. | 413 | * be inside due to u64 alignment of output. |
414 | */ | 414 | */ |
415 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | 415 | if ((old & md->mask) + size != ((old + size) & md->mask)) { |
416 | unsigned int offset = old; | 416 | unsigned int offset = old; |
417 | unsigned int len = min(sizeof(*event), size), cpy; | 417 | unsigned int len = min(sizeof(*event), size), cpy; |
418 | void *dst = &evlist->event_copy; | 418 | void *dst = &evlist->event_copy; |
419 | 419 | ||
420 | do { | 420 | do { |
421 | cpy = min(md->mask + 1 - (offset & md->mask), len); | 421 | cpy = min(md->mask + 1 - (offset & md->mask), len); |
422 | memcpy(dst, &data[offset & md->mask], cpy); | 422 | memcpy(dst, &data[offset & md->mask], cpy); |
423 | offset += cpy; | 423 | offset += cpy; |
424 | dst += cpy; | 424 | dst += cpy; |
425 | len -= cpy; | 425 | len -= cpy; |
426 | } while (len); | 426 | } while (len); |
427 | 427 | ||
428 | event = &evlist->event_copy; | 428 | event = &evlist->event_copy; |
429 | } | 429 | } |
430 | 430 | ||
431 | old += size; | 431 | old += size; |
432 | } | 432 | } |
433 | 433 | ||
434 | md->prev = old; | 434 | md->prev = old; |
435 | 435 | ||
436 | if (!evlist->overwrite) | 436 | if (!evlist->overwrite) |
437 | perf_mmap__write_tail(md, old); | 437 | perf_mmap__write_tail(md, old); |
438 | 438 | ||
439 | return event; | 439 | return event; |
440 | } | 440 | } |
441 | 441 | ||
442 | void perf_evlist__munmap(struct perf_evlist *evlist) | 442 | void perf_evlist__munmap(struct perf_evlist *evlist) |
443 | { | 443 | { |
444 | int i; | 444 | int i; |
445 | 445 | ||
446 | for (i = 0; i < evlist->nr_mmaps; i++) { | 446 | for (i = 0; i < evlist->nr_mmaps; i++) { |
447 | if (evlist->mmap[i].base != NULL) { | 447 | if (evlist->mmap[i].base != NULL) { |
448 | munmap(evlist->mmap[i].base, evlist->mmap_len); | 448 | munmap(evlist->mmap[i].base, evlist->mmap_len); |
449 | evlist->mmap[i].base = NULL; | 449 | evlist->mmap[i].base = NULL; |
450 | } | 450 | } |
451 | } | 451 | } |
452 | 452 | ||
453 | free(evlist->mmap); | 453 | free(evlist->mmap); |
454 | evlist->mmap = NULL; | 454 | evlist->mmap = NULL; |
455 | } | 455 | } |
456 | 456 | ||
457 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | 457 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) |
458 | { | 458 | { |
459 | evlist->nr_mmaps = evlist->cpus->nr; | 459 | evlist->nr_mmaps = evlist->cpus->nr; |
460 | if (evlist->cpus->map[0] == -1) | 460 | if (evlist->cpus->map[0] == -1) |
461 | evlist->nr_mmaps = evlist->threads->nr; | 461 | evlist->nr_mmaps = evlist->threads->nr; |
462 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); | 462 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); |
463 | return evlist->mmap != NULL ? 0 : -ENOMEM; | 463 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
464 | } | 464 | } |
465 | 465 | ||
466 | static int __perf_evlist__mmap(struct perf_evlist *evlist, | 466 | static int __perf_evlist__mmap(struct perf_evlist *evlist, |
467 | int idx, int prot, int mask, int fd) | 467 | int idx, int prot, int mask, int fd) |
468 | { | 468 | { |
469 | evlist->mmap[idx].prev = 0; | 469 | evlist->mmap[idx].prev = 0; |
470 | evlist->mmap[idx].mask = mask; | 470 | evlist->mmap[idx].mask = mask; |
471 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, | 471 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, |
472 | MAP_SHARED, fd, 0); | 472 | MAP_SHARED, fd, 0); |
473 | if (evlist->mmap[idx].base == MAP_FAILED) { | 473 | if (evlist->mmap[idx].base == MAP_FAILED) { |
474 | evlist->mmap[idx].base = NULL; | 474 | evlist->mmap[idx].base = NULL; |
475 | return -1; | 475 | return -1; |
476 | } | 476 | } |
477 | 477 | ||
478 | perf_evlist__add_pollfd(evlist, fd); | 478 | perf_evlist__add_pollfd(evlist, fd); |
479 | return 0; | 479 | return 0; |
480 | } | 480 | } |
481 | 481 | ||
482 | static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask) | 482 | static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask) |
483 | { | 483 | { |
484 | struct perf_evsel *evsel; | 484 | struct perf_evsel *evsel; |
485 | int cpu, thread; | 485 | int cpu, thread; |
486 | 486 | ||
487 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 487 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { |
488 | int output = -1; | 488 | int output = -1; |
489 | 489 | ||
490 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 490 | for (thread = 0; thread < evlist->threads->nr; thread++) { |
491 | list_for_each_entry(evsel, &evlist->entries, node) { | 491 | list_for_each_entry(evsel, &evlist->entries, node) { |
492 | int fd = FD(evsel, cpu, thread); | 492 | int fd = FD(evsel, cpu, thread); |
493 | 493 | ||
494 | if (output == -1) { | 494 | if (output == -1) { |
495 | output = fd; | 495 | output = fd; |
496 | if (__perf_evlist__mmap(evlist, cpu, | 496 | if (__perf_evlist__mmap(evlist, cpu, |
497 | prot, mask, output) < 0) | 497 | prot, mask, output) < 0) |
498 | goto out_unmap; | 498 | goto out_unmap; |
499 | } else { | 499 | } else { |
500 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0) | 500 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0) |
501 | goto out_unmap; | 501 | goto out_unmap; |
502 | } | 502 | } |
503 | 503 | ||
504 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 504 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
505 | perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) | 505 | perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) |
506 | goto out_unmap; | 506 | goto out_unmap; |
507 | } | 507 | } |
508 | } | 508 | } |
509 | } | 509 | } |
510 | 510 | ||
511 | return 0; | 511 | return 0; |
512 | 512 | ||
513 | out_unmap: | 513 | out_unmap: |
514 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 514 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { |
515 | if (evlist->mmap[cpu].base != NULL) { | 515 | if (evlist->mmap[cpu].base != NULL) { |
516 | munmap(evlist->mmap[cpu].base, evlist->mmap_len); | 516 | munmap(evlist->mmap[cpu].base, evlist->mmap_len); |
517 | evlist->mmap[cpu].base = NULL; | 517 | evlist->mmap[cpu].base = NULL; |
518 | } | 518 | } |
519 | } | 519 | } |
520 | return -1; | 520 | return -1; |
521 | } | 521 | } |
522 | 522 | ||
523 | static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask) | 523 | static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask) |
524 | { | 524 | { |
525 | struct perf_evsel *evsel; | 525 | struct perf_evsel *evsel; |
526 | int thread; | 526 | int thread; |
527 | 527 | ||
528 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 528 | for (thread = 0; thread < evlist->threads->nr; thread++) { |
529 | int output = -1; | 529 | int output = -1; |
530 | 530 | ||
531 | list_for_each_entry(evsel, &evlist->entries, node) { | 531 | list_for_each_entry(evsel, &evlist->entries, node) { |
532 | int fd = FD(evsel, 0, thread); | 532 | int fd = FD(evsel, 0, thread); |
533 | 533 | ||
534 | if (output == -1) { | 534 | if (output == -1) { |
535 | output = fd; | 535 | output = fd; |
536 | if (__perf_evlist__mmap(evlist, thread, | 536 | if (__perf_evlist__mmap(evlist, thread, |
537 | prot, mask, output) < 0) | 537 | prot, mask, output) < 0) |
538 | goto out_unmap; | 538 | goto out_unmap; |
539 | } else { | 539 | } else { |
540 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0) | 540 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0) |
541 | goto out_unmap; | 541 | goto out_unmap; |
542 | } | 542 | } |
543 | 543 | ||
544 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 544 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
545 | perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0) | 545 | perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0) |
546 | goto out_unmap; | 546 | goto out_unmap; |
547 | } | 547 | } |
548 | } | 548 | } |
549 | 549 | ||
550 | return 0; | 550 | return 0; |
551 | 551 | ||
552 | out_unmap: | 552 | out_unmap: |
553 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 553 | for (thread = 0; thread < evlist->threads->nr; thread++) { |
554 | if (evlist->mmap[thread].base != NULL) { | 554 | if (evlist->mmap[thread].base != NULL) { |
555 | munmap(evlist->mmap[thread].base, evlist->mmap_len); | 555 | munmap(evlist->mmap[thread].base, evlist->mmap_len); |
556 | evlist->mmap[thread].base = NULL; | 556 | evlist->mmap[thread].base = NULL; |
557 | } | 557 | } |
558 | } | 558 | } |
559 | return -1; | 559 | return -1; |
560 | } | 560 | } |
561 | 561 | ||
562 | /** perf_evlist__mmap - Create per cpu maps to receive events | 562 | /** perf_evlist__mmap - Create per cpu maps to receive events |
563 | * | 563 | * |
564 | * @evlist - list of events | 564 | * @evlist - list of events |
565 | * @pages - map length in pages | 565 | * @pages - map length in pages |
566 | * @overwrite - overwrite older events? | 566 | * @overwrite - overwrite older events? |
567 | * | 567 | * |
568 | * If overwrite is false the user needs to signal event consuption using: | 568 | * If overwrite is false the user needs to signal event consuption using: |
569 | * | 569 | * |
570 | * struct perf_mmap *m = &evlist->mmap[cpu]; | 570 | * struct perf_mmap *m = &evlist->mmap[cpu]; |
571 | * unsigned int head = perf_mmap__read_head(m); | 571 | * unsigned int head = perf_mmap__read_head(m); |
572 | * | 572 | * |
573 | * perf_mmap__write_tail(m, head) | 573 | * perf_mmap__write_tail(m, head) |
574 | * | 574 | * |
575 | * Using perf_evlist__read_on_cpu does this automatically. | 575 | * Using perf_evlist__read_on_cpu does this automatically. |
576 | */ | 576 | */ |
577 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | 577 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, |
578 | bool overwrite) | 578 | bool overwrite) |
579 | { | 579 | { |
580 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); | 580 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); |
581 | struct perf_evsel *evsel; | 581 | struct perf_evsel *evsel; |
582 | const struct cpu_map *cpus = evlist->cpus; | 582 | const struct cpu_map *cpus = evlist->cpus; |
583 | const struct thread_map *threads = evlist->threads; | 583 | const struct thread_map *threads = evlist->threads; |
584 | int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; | 584 | int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; |
585 | 585 | ||
586 | /* 512 kiB: default amount of unprivileged mlocked memory */ | 586 | /* 512 kiB: default amount of unprivileged mlocked memory */ |
587 | if (pages == UINT_MAX) | 587 | if (pages == UINT_MAX) |
588 | pages = (512 * 1024) / page_size; | 588 | pages = (512 * 1024) / page_size; |
589 | else if (!is_power_of_2(pages)) | 589 | else if (!is_power_of_2(pages)) |
590 | return -EINVAL; | 590 | return -EINVAL; |
591 | 591 | ||
592 | mask = pages * page_size - 1; | 592 | mask = pages * page_size - 1; |
593 | 593 | ||
594 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) | 594 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) |
595 | return -ENOMEM; | 595 | return -ENOMEM; |
596 | 596 | ||
597 | if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0) | 597 | if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0) |
598 | return -ENOMEM; | 598 | return -ENOMEM; |
599 | 599 | ||
600 | evlist->overwrite = overwrite; | 600 | evlist->overwrite = overwrite; |
601 | evlist->mmap_len = (pages + 1) * page_size; | 601 | evlist->mmap_len = (pages + 1) * page_size; |
602 | 602 | ||
603 | list_for_each_entry(evsel, &evlist->entries, node) { | 603 | list_for_each_entry(evsel, &evlist->entries, node) { |
604 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 604 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
605 | evsel->sample_id == NULL && | 605 | evsel->sample_id == NULL && |
606 | perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0) | 606 | perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0) |
607 | return -ENOMEM; | 607 | return -ENOMEM; |
608 | } | 608 | } |
609 | 609 | ||
610 | if (evlist->cpus->map[0] == -1) | 610 | if (evlist->cpus->map[0] == -1) |
611 | return perf_evlist__mmap_per_thread(evlist, prot, mask); | 611 | return perf_evlist__mmap_per_thread(evlist, prot, mask); |
612 | 612 | ||
613 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); | 613 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); |
614 | } | 614 | } |
615 | 615 | ||
616 | int perf_evlist__create_maps(struct perf_evlist *evlist, | 616 | int perf_evlist__create_maps(struct perf_evlist *evlist, |
617 | struct perf_target *target) | 617 | struct perf_target *target) |
618 | { | 618 | { |
619 | evlist->threads = thread_map__new_str(target->pid, target->tid, | 619 | evlist->threads = thread_map__new_str(target->pid, target->tid, |
620 | target->uid); | 620 | target->uid); |
621 | 621 | ||
622 | if (evlist->threads == NULL) | 622 | if (evlist->threads == NULL) |
623 | return -1; | 623 | return -1; |
624 | 624 | ||
625 | if (perf_target__has_task(target)) | 625 | if (perf_target__has_task(target)) |
626 | evlist->cpus = cpu_map__dummy_new(); | 626 | evlist->cpus = cpu_map__dummy_new(); |
627 | else if (!perf_target__has_cpu(target) && !target->uses_mmap) | 627 | else if (!perf_target__has_cpu(target) && !target->uses_mmap) |
628 | evlist->cpus = cpu_map__dummy_new(); | 628 | evlist->cpus = cpu_map__dummy_new(); |
629 | else | 629 | else |
630 | evlist->cpus = cpu_map__new(target->cpu_list); | 630 | evlist->cpus = cpu_map__new(target->cpu_list); |
631 | 631 | ||
632 | if (evlist->cpus == NULL) | 632 | if (evlist->cpus == NULL) |
633 | goto out_delete_threads; | 633 | goto out_delete_threads; |
634 | 634 | ||
635 | return 0; | 635 | return 0; |
636 | 636 | ||
637 | out_delete_threads: | 637 | out_delete_threads: |
638 | thread_map__delete(evlist->threads); | 638 | thread_map__delete(evlist->threads); |
639 | return -1; | 639 | return -1; |
640 | } | 640 | } |
641 | 641 | ||
642 | void perf_evlist__delete_maps(struct perf_evlist *evlist) | 642 | void perf_evlist__delete_maps(struct perf_evlist *evlist) |
643 | { | 643 | { |
644 | cpu_map__delete(evlist->cpus); | 644 | cpu_map__delete(evlist->cpus); |
645 | thread_map__delete(evlist->threads); | 645 | thread_map__delete(evlist->threads); |
646 | evlist->cpus = NULL; | 646 | evlist->cpus = NULL; |
647 | evlist->threads = NULL; | 647 | evlist->threads = NULL; |
648 | } | 648 | } |
649 | 649 | ||
650 | int perf_evlist__set_filters(struct perf_evlist *evlist) | 650 | int perf_evlist__set_filters(struct perf_evlist *evlist) |
651 | { | 651 | { |
652 | const struct thread_map *threads = evlist->threads; | 652 | const struct thread_map *threads = evlist->threads; |
653 | const struct cpu_map *cpus = evlist->cpus; | 653 | const struct cpu_map *cpus = evlist->cpus; |
654 | struct perf_evsel *evsel; | 654 | struct perf_evsel *evsel; |
655 | char *filter; | 655 | char *filter; |
656 | int thread; | 656 | int thread; |
657 | int cpu; | 657 | int cpu; |
658 | int err; | 658 | int err; |
659 | int fd; | 659 | int fd; |
660 | 660 | ||
661 | list_for_each_entry(evsel, &evlist->entries, node) { | 661 | list_for_each_entry(evsel, &evlist->entries, node) { |
662 | filter = evsel->filter; | 662 | filter = evsel->filter; |
663 | if (!filter) | 663 | if (!filter) |
664 | continue; | 664 | continue; |
665 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 665 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
666 | for (thread = 0; thread < threads->nr; thread++) { | 666 | for (thread = 0; thread < threads->nr; thread++) { |
667 | fd = FD(evsel, cpu, thread); | 667 | fd = FD(evsel, cpu, thread); |
668 | err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); | 668 | err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); |
669 | if (err) | 669 | if (err) |
670 | return err; | 670 | return err; |
671 | } | 671 | } |
672 | } | 672 | } |
673 | } | 673 | } |
674 | 674 | ||
675 | return 0; | 675 | return 0; |
676 | } | 676 | } |
677 | 677 | ||
678 | bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist) | 678 | bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist) |
679 | { | 679 | { |
680 | struct perf_evsel *pos, *first; | 680 | struct perf_evsel *pos, *first; |
681 | 681 | ||
682 | pos = first = list_entry(evlist->entries.next, struct perf_evsel, node); | 682 | pos = first = list_entry(evlist->entries.next, struct perf_evsel, node); |
683 | 683 | ||
684 | list_for_each_entry_continue(pos, &evlist->entries, node) { | 684 | list_for_each_entry_continue(pos, &evlist->entries, node) { |
685 | if (first->attr.sample_type != pos->attr.sample_type) | 685 | if (first->attr.sample_type != pos->attr.sample_type) |
686 | return false; | 686 | return false; |
687 | } | 687 | } |
688 | 688 | ||
689 | return true; | 689 | return true; |
690 | } | 690 | } |
691 | 691 | ||
692 | u64 perf_evlist__sample_type(const struct perf_evlist *evlist) | 692 | u64 perf_evlist__sample_type(const struct perf_evlist *evlist) |
693 | { | 693 | { |
694 | struct perf_evsel *first; | 694 | struct perf_evsel *first; |
695 | 695 | ||
696 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 696 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
697 | return first->attr.sample_type; | 697 | return first->attr.sample_type; |
698 | } | 698 | } |
699 | 699 | ||
700 | u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist) | 700 | u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist) |
701 | { | 701 | { |
702 | struct perf_evsel *first; | 702 | struct perf_evsel *first; |
703 | struct perf_sample *data; | 703 | struct perf_sample *data; |
704 | u64 sample_type; | 704 | u64 sample_type; |
705 | u16 size = 0; | 705 | u16 size = 0; |
706 | 706 | ||
707 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 707 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
708 | 708 | ||
709 | if (!first->attr.sample_id_all) | 709 | if (!first->attr.sample_id_all) |
710 | goto out; | 710 | goto out; |
711 | 711 | ||
712 | sample_type = first->attr.sample_type; | 712 | sample_type = first->attr.sample_type; |
713 | 713 | ||
714 | if (sample_type & PERF_SAMPLE_TID) | 714 | if (sample_type & PERF_SAMPLE_TID) |
715 | size += sizeof(data->tid) * 2; | 715 | size += sizeof(data->tid) * 2; |
716 | 716 | ||
717 | if (sample_type & PERF_SAMPLE_TIME) | 717 | if (sample_type & PERF_SAMPLE_TIME) |
718 | size += sizeof(data->time); | 718 | size += sizeof(data->time); |
719 | 719 | ||
720 | if (sample_type & PERF_SAMPLE_ID) | 720 | if (sample_type & PERF_SAMPLE_ID) |
721 | size += sizeof(data->id); | 721 | size += sizeof(data->id); |
722 | 722 | ||
723 | if (sample_type & PERF_SAMPLE_STREAM_ID) | 723 | if (sample_type & PERF_SAMPLE_STREAM_ID) |
724 | size += sizeof(data->stream_id); | 724 | size += sizeof(data->stream_id); |
725 | 725 | ||
726 | if (sample_type & PERF_SAMPLE_CPU) | 726 | if (sample_type & PERF_SAMPLE_CPU) |
727 | size += sizeof(data->cpu) * 2; | 727 | size += sizeof(data->cpu) * 2; |
728 | out: | 728 | out: |
729 | return size; | 729 | return size; |
730 | } | 730 | } |
731 | 731 | ||
732 | bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist) | 732 | bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist) |
733 | { | 733 | { |
734 | struct perf_evsel *pos, *first; | 734 | struct perf_evsel *pos, *first; |
735 | 735 | ||
736 | pos = first = list_entry(evlist->entries.next, struct perf_evsel, node); | 736 | pos = first = list_entry(evlist->entries.next, struct perf_evsel, node); |
737 | 737 | ||
738 | list_for_each_entry_continue(pos, &evlist->entries, node) { | 738 | list_for_each_entry_continue(pos, &evlist->entries, node) { |
739 | if (first->attr.sample_id_all != pos->attr.sample_id_all) | 739 | if (first->attr.sample_id_all != pos->attr.sample_id_all) |
740 | return false; | 740 | return false; |
741 | } | 741 | } |
742 | 742 | ||
743 | return true; | 743 | return true; |
744 | } | 744 | } |
745 | 745 | ||
746 | bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) | 746 | bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) |
747 | { | 747 | { |
748 | struct perf_evsel *first; | 748 | struct perf_evsel *first; |
749 | 749 | ||
750 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 750 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
751 | return first->attr.sample_id_all; | 751 | return first->attr.sample_id_all; |
752 | } | 752 | } |
753 | 753 | ||
754 | void perf_evlist__set_selected(struct perf_evlist *evlist, | 754 | void perf_evlist__set_selected(struct perf_evlist *evlist, |
755 | struct perf_evsel *evsel) | 755 | struct perf_evsel *evsel) |
756 | { | 756 | { |
757 | evlist->selected = evsel; | 757 | evlist->selected = evsel; |
758 | } | 758 | } |
759 | 759 | ||
760 | int perf_evlist__open(struct perf_evlist *evlist, bool group) | 760 | int perf_evlist__open(struct perf_evlist *evlist, bool group) |
761 | { | 761 | { |
762 | struct perf_evsel *evsel, *first; | 762 | struct perf_evsel *evsel, *first; |
763 | int err, ncpus, nthreads; | 763 | int err, ncpus, nthreads; |
764 | 764 | ||
765 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 765 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
766 | 766 | ||
767 | list_for_each_entry(evsel, &evlist->entries, node) { | 767 | list_for_each_entry(evsel, &evlist->entries, node) { |
768 | struct xyarray *group_fd = NULL; | 768 | struct xyarray *group_fd = NULL; |
769 | 769 | ||
770 | if (group && evsel != first) | 770 | if (group && evsel != first) |
771 | group_fd = first->fd; | 771 | group_fd = first->fd; |
772 | 772 | ||
773 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads, | 773 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads, |
774 | group, group_fd); | 774 | group, group_fd); |
775 | if (err < 0) | 775 | if (err < 0) |
776 | goto out_err; | 776 | goto out_err; |
777 | } | 777 | } |
778 | 778 | ||
779 | return 0; | 779 | return 0; |
780 | out_err: | 780 | out_err: |
781 | ncpus = evlist->cpus ? evlist->cpus->nr : 1; | 781 | ncpus = evlist->cpus ? evlist->cpus->nr : 1; |
782 | nthreads = evlist->threads ? evlist->threads->nr : 1; | 782 | nthreads = evlist->threads ? evlist->threads->nr : 1; |
783 | 783 | ||
784 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | 784 | list_for_each_entry_reverse(evsel, &evlist->entries, node) |
785 | perf_evsel__close(evsel, ncpus, nthreads); | 785 | perf_evsel__close(evsel, ncpus, nthreads); |
786 | 786 | ||
787 | errno = -err; | 787 | errno = -err; |
788 | return err; | 788 | return err; |
789 | } | 789 | } |
790 | 790 | ||
791 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 791 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
792 | struct perf_record_opts *opts, | 792 | struct perf_record_opts *opts, |
793 | const char *argv[]) | 793 | const char *argv[]) |
794 | { | 794 | { |
795 | int child_ready_pipe[2], go_pipe[2]; | 795 | int child_ready_pipe[2], go_pipe[2]; |
796 | char bf; | 796 | char bf; |
797 | 797 | ||
798 | if (pipe(child_ready_pipe) < 0) { | 798 | if (pipe(child_ready_pipe) < 0) { |
799 | perror("failed to create 'ready' pipe"); | 799 | perror("failed to create 'ready' pipe"); |
800 | return -1; | 800 | return -1; |
801 | } | 801 | } |
802 | 802 | ||
803 | if (pipe(go_pipe) < 0) { | 803 | if (pipe(go_pipe) < 0) { |
804 | perror("failed to create 'go' pipe"); | 804 | perror("failed to create 'go' pipe"); |
805 | goto out_close_ready_pipe; | 805 | goto out_close_ready_pipe; |
806 | } | 806 | } |
807 | 807 | ||
808 | evlist->workload.pid = fork(); | 808 | evlist->workload.pid = fork(); |
809 | if (evlist->workload.pid < 0) { | 809 | if (evlist->workload.pid < 0) { |
810 | perror("failed to fork"); | 810 | perror("failed to fork"); |
811 | goto out_close_pipes; | 811 | goto out_close_pipes; |
812 | } | 812 | } |
813 | 813 | ||
814 | if (!evlist->workload.pid) { | 814 | if (!evlist->workload.pid) { |
815 | if (opts->pipe_output) | 815 | if (opts->pipe_output) |
816 | dup2(2, 1); | 816 | dup2(2, 1); |
817 | 817 | ||
818 | close(child_ready_pipe[0]); | 818 | close(child_ready_pipe[0]); |
819 | close(go_pipe[1]); | 819 | close(go_pipe[1]); |
820 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); | 820 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); |
821 | 821 | ||
822 | /* | 822 | /* |
823 | * Do a dummy execvp to get the PLT entry resolved, | 823 | * Do a dummy execvp to get the PLT entry resolved, |
824 | * so we avoid the resolver overhead on the real | 824 | * so we avoid the resolver overhead on the real |
825 | * execvp call. | 825 | * execvp call. |
826 | */ | 826 | */ |
827 | execvp("", (char **)argv); | 827 | execvp("", (char **)argv); |
828 | 828 | ||
829 | /* | 829 | /* |
830 | * Tell the parent we're ready to go | 830 | * Tell the parent we're ready to go |
831 | */ | 831 | */ |
832 | close(child_ready_pipe[1]); | 832 | close(child_ready_pipe[1]); |
833 | 833 | ||
834 | /* | 834 | /* |
835 | * Wait until the parent tells us to go. | 835 | * Wait until the parent tells us to go. |
836 | */ | 836 | */ |
837 | if (read(go_pipe[0], &bf, 1) == -1) | 837 | if (read(go_pipe[0], &bf, 1) == -1) |
838 | perror("unable to read pipe"); | 838 | perror("unable to read pipe"); |
839 | 839 | ||
840 | execvp(argv[0], (char **)argv); | 840 | execvp(argv[0], (char **)argv); |
841 | 841 | ||
842 | perror(argv[0]); | 842 | perror(argv[0]); |
843 | kill(getppid(), SIGUSR1); | 843 | kill(getppid(), SIGUSR1); |
844 | exit(-1); | 844 | exit(-1); |
845 | } | 845 | } |
846 | 846 | ||
847 | if (perf_target__none(&opts->target)) | 847 | if (perf_target__none(&opts->target)) |
848 | evlist->threads->map[0] = evlist->workload.pid; | 848 | evlist->threads->map[0] = evlist->workload.pid; |
849 | 849 | ||
850 | close(child_ready_pipe[1]); | 850 | close(child_ready_pipe[1]); |
851 | close(go_pipe[0]); | 851 | close(go_pipe[0]); |
852 | /* | 852 | /* |
853 | * wait for child to settle | 853 | * wait for child to settle |
854 | */ | 854 | */ |
855 | if (read(child_ready_pipe[0], &bf, 1) == -1) { | 855 | if (read(child_ready_pipe[0], &bf, 1) == -1) { |
856 | perror("unable to read pipe"); | 856 | perror("unable to read pipe"); |
857 | goto out_close_pipes; | 857 | goto out_close_pipes; |
858 | } | 858 | } |
859 | 859 | ||
860 | evlist->workload.cork_fd = go_pipe[1]; | 860 | evlist->workload.cork_fd = go_pipe[1]; |
861 | close(child_ready_pipe[0]); | 861 | close(child_ready_pipe[0]); |
862 | return 0; | 862 | return 0; |
863 | 863 | ||
864 | out_close_pipes: | 864 | out_close_pipes: |
865 | close(go_pipe[0]); | 865 | close(go_pipe[0]); |
866 | close(go_pipe[1]); | 866 | close(go_pipe[1]); |
867 | out_close_ready_pipe: | 867 | out_close_ready_pipe: |
868 | close(child_ready_pipe[0]); | 868 | close(child_ready_pipe[0]); |
869 | close(child_ready_pipe[1]); | 869 | close(child_ready_pipe[1]); |
870 | return -1; | 870 | return -1; |
871 | } | 871 | } |
872 | 872 | ||
873 | int perf_evlist__start_workload(struct perf_evlist *evlist) | 873 | int perf_evlist__start_workload(struct perf_evlist *evlist) |
874 | { | 874 | { |
875 | if (evlist->workload.cork_fd > 0) { | 875 | if (evlist->workload.cork_fd > 0) { |
876 | /* | 876 | /* |
877 | * Remove the cork, let it rip! | 877 | * Remove the cork, let it rip! |
878 | */ | 878 | */ |
879 | return close(evlist->workload.cork_fd); | 879 | return close(evlist->workload.cork_fd); |
880 | } | 880 | } |
881 | 881 | ||
882 | return 0; | 882 | return 0; |
883 | } | 883 | } |
884 | 884 | ||
885 | int perf_evlist__parse_sample(struct perf_evlist *evlist, | 885 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, |
886 | const union perf_event *event, | ||
887 | struct perf_sample *sample, bool swapped) | 886 | struct perf_sample *sample, bool swapped) |
888 | { | 887 | { |
889 | struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node); | 888 | struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node); |
890 | return perf_event__parse_sample(event, e->attr.sample_type, e->sample_size, | 889 | return perf_evsel__parse_sample(e, event, sample, swapped); |
891 | e->attr.sample_id_all, sample, swapped); | ||
892 | } | 890 | } |
893 | 891 |
tools/perf/util/evlist.h
1 | #ifndef __PERF_EVLIST_H | 1 | #ifndef __PERF_EVLIST_H |
2 | #define __PERF_EVLIST_H 1 | 2 | #define __PERF_EVLIST_H 1 |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <stdio.h> | 5 | #include <stdio.h> |
6 | #include "../perf.h" | 6 | #include "../perf.h" |
7 | #include "event.h" | 7 | #include "event.h" |
8 | #include "util.h" | 8 | #include "util.h" |
9 | #include <unistd.h> | 9 | #include <unistd.h> |
10 | 10 | ||
11 | struct pollfd; | 11 | struct pollfd; |
12 | struct thread_map; | 12 | struct thread_map; |
13 | struct cpu_map; | 13 | struct cpu_map; |
14 | struct perf_record_opts; | 14 | struct perf_record_opts; |
15 | 15 | ||
16 | #define PERF_EVLIST__HLIST_BITS 8 | 16 | #define PERF_EVLIST__HLIST_BITS 8 |
17 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) | 17 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) |
18 | 18 | ||
19 | struct perf_evlist { | 19 | struct perf_evlist { |
20 | struct list_head entries; | 20 | struct list_head entries; |
21 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; | 21 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; |
22 | int nr_entries; | 22 | int nr_entries; |
23 | int nr_fds; | 23 | int nr_fds; |
24 | int nr_mmaps; | 24 | int nr_mmaps; |
25 | int mmap_len; | 25 | int mmap_len; |
26 | struct { | 26 | struct { |
27 | int cork_fd; | 27 | int cork_fd; |
28 | pid_t pid; | 28 | pid_t pid; |
29 | } workload; | 29 | } workload; |
30 | bool overwrite; | 30 | bool overwrite; |
31 | union perf_event event_copy; | 31 | union perf_event event_copy; |
32 | struct perf_mmap *mmap; | 32 | struct perf_mmap *mmap; |
33 | struct pollfd *pollfd; | 33 | struct pollfd *pollfd; |
34 | struct thread_map *threads; | 34 | struct thread_map *threads; |
35 | struct cpu_map *cpus; | 35 | struct cpu_map *cpus; |
36 | struct perf_evsel *selected; | 36 | struct perf_evsel *selected; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct perf_evsel_str_handler { | 39 | struct perf_evsel_str_handler { |
40 | const char *name; | 40 | const char *name; |
41 | void *handler; | 41 | void *handler; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct perf_evsel; | 44 | struct perf_evsel; |
45 | 45 | ||
46 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 46 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, |
47 | struct thread_map *threads); | 47 | struct thread_map *threads); |
48 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | 48 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, |
49 | struct thread_map *threads); | 49 | struct thread_map *threads); |
50 | void perf_evlist__exit(struct perf_evlist *evlist); | 50 | void perf_evlist__exit(struct perf_evlist *evlist); |
51 | void perf_evlist__delete(struct perf_evlist *evlist); | 51 | void perf_evlist__delete(struct perf_evlist *evlist); |
52 | 52 | ||
53 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); | 53 | void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); |
54 | int perf_evlist__add_default(struct perf_evlist *evlist); | 54 | int perf_evlist__add_default(struct perf_evlist *evlist); |
55 | int perf_evlist__add_attrs(struct perf_evlist *evlist, | 55 | int perf_evlist__add_attrs(struct perf_evlist *evlist, |
56 | struct perf_event_attr *attrs, size_t nr_attrs); | 56 | struct perf_event_attr *attrs, size_t nr_attrs); |
57 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, | 57 | int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, |
58 | struct perf_event_attr *attrs, size_t nr_attrs); | 58 | struct perf_event_attr *attrs, size_t nr_attrs); |
59 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | 59 | int perf_evlist__add_tracepoints(struct perf_evlist *evlist, |
60 | const char *tracepoints[], size_t nr_tracepoints); | 60 | const char *tracepoints[], size_t nr_tracepoints); |
61 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | 61 | int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, |
62 | const struct perf_evsel_str_handler *assocs, | 62 | const struct perf_evsel_str_handler *assocs, |
63 | size_t nr_assocs); | 63 | size_t nr_assocs); |
64 | 64 | ||
65 | #define perf_evlist__add_attrs_array(evlist, array) \ | 65 | #define perf_evlist__add_attrs_array(evlist, array) \ |
66 | perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) | 66 | perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) |
67 | #define perf_evlist__add_default_attrs(evlist, array) \ | 67 | #define perf_evlist__add_default_attrs(evlist, array) \ |
68 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) | 68 | __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) |
69 | 69 | ||
70 | #define perf_evlist__add_tracepoints_array(evlist, array) \ | 70 | #define perf_evlist__add_tracepoints_array(evlist, array) \ |
71 | perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) | 71 | perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) |
72 | 72 | ||
73 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ | 73 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ |
74 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) | 74 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) |
75 | 75 | ||
76 | struct perf_evsel * | 76 | struct perf_evsel * |
77 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); | 77 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); |
78 | 78 | ||
79 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, | 79 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, |
80 | int cpu, int thread, u64 id); | 80 | int cpu, int thread, u64 id); |
81 | 81 | ||
82 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); | 82 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); |
83 | 83 | ||
84 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | 84 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); |
85 | 85 | ||
86 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | 86 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); |
87 | 87 | ||
88 | int perf_evlist__open(struct perf_evlist *evlist, bool group); | 88 | int perf_evlist__open(struct perf_evlist *evlist, bool group); |
89 | 89 | ||
90 | void perf_evlist__config_attrs(struct perf_evlist *evlist, | 90 | void perf_evlist__config_attrs(struct perf_evlist *evlist, |
91 | struct perf_record_opts *opts); | 91 | struct perf_record_opts *opts); |
92 | 92 | ||
93 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 93 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
94 | struct perf_record_opts *opts, | 94 | struct perf_record_opts *opts, |
95 | const char *argv[]); | 95 | const char *argv[]); |
96 | int perf_evlist__start_workload(struct perf_evlist *evlist); | 96 | int perf_evlist__start_workload(struct perf_evlist *evlist); |
97 | 97 | ||
98 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | 98 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, |
99 | bool overwrite); | 99 | bool overwrite); |
100 | void perf_evlist__munmap(struct perf_evlist *evlist); | 100 | void perf_evlist__munmap(struct perf_evlist *evlist); |
101 | 101 | ||
102 | void perf_evlist__disable(struct perf_evlist *evlist); | 102 | void perf_evlist__disable(struct perf_evlist *evlist); |
103 | void perf_evlist__enable(struct perf_evlist *evlist); | 103 | void perf_evlist__enable(struct perf_evlist *evlist); |
104 | 104 | ||
105 | void perf_evlist__set_selected(struct perf_evlist *evlist, | 105 | void perf_evlist__set_selected(struct perf_evlist *evlist, |
106 | struct perf_evsel *evsel); | 106 | struct perf_evsel *evsel); |
107 | 107 | ||
108 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | 108 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, |
109 | struct cpu_map *cpus, | 109 | struct cpu_map *cpus, |
110 | struct thread_map *threads) | 110 | struct thread_map *threads) |
111 | { | 111 | { |
112 | evlist->cpus = cpus; | 112 | evlist->cpus = cpus; |
113 | evlist->threads = threads; | 113 | evlist->threads = threads; |
114 | } | 114 | } |
115 | 115 | ||
116 | int perf_evlist__create_maps(struct perf_evlist *evlist, | 116 | int perf_evlist__create_maps(struct perf_evlist *evlist, |
117 | struct perf_target *target); | 117 | struct perf_target *target); |
118 | void perf_evlist__delete_maps(struct perf_evlist *evlist); | 118 | void perf_evlist__delete_maps(struct perf_evlist *evlist); |
119 | int perf_evlist__set_filters(struct perf_evlist *evlist); | 119 | int perf_evlist__set_filters(struct perf_evlist *evlist); |
120 | 120 | ||
121 | u64 perf_evlist__sample_type(const struct perf_evlist *evlist); | 121 | u64 perf_evlist__sample_type(const struct perf_evlist *evlist); |
122 | bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); | 122 | bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); |
123 | u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist); | 123 | u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist); |
124 | 124 | ||
125 | int perf_evlist__parse_sample(struct perf_evlist *evlist, | 125 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, |
126 | const union perf_event *event, | ||
127 | struct perf_sample *sample, bool swapped); | 126 | struct perf_sample *sample, bool swapped); |
128 | 127 | ||
129 | bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); | 128 | bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); |
130 | bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); | 129 | bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); |
131 | 130 | ||
132 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, | 131 | void perf_evlist__splice_list_tail(struct perf_evlist *evlist, |
133 | struct list_head *list, | 132 | struct list_head *list, |
134 | int nr_entries); | 133 | int nr_entries); |
135 | 134 | ||
136 | #endif /* __PERF_EVLIST_H */ | 135 | #endif /* __PERF_EVLIST_H */ |
137 | 136 |
tools/perf/util/evsel.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | 2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> |
3 | * | 3 | * |
4 | * Parts came from builtin-{top,stat,record}.c, see those files for further | 4 | * Parts came from builtin-{top,stat,record}.c, see those files for further |
5 | * copyright notes. | 5 | * copyright notes. |
6 | * | 6 | * |
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <byteswap.h> | 10 | #include <byteswap.h> |
11 | #include "asm/bug.h" | 11 | #include "asm/bug.h" |
12 | #include "evsel.h" | 12 | #include "evsel.h" |
13 | #include "evlist.h" | 13 | #include "evlist.h" |
14 | #include "util.h" | 14 | #include "util.h" |
15 | #include "cpumap.h" | 15 | #include "cpumap.h" |
16 | #include "thread_map.h" | 16 | #include "thread_map.h" |
17 | #include "target.h" | 17 | #include "target.h" |
18 | #include "../../../include/linux/hw_breakpoint.h" | 18 | #include "../../../include/linux/hw_breakpoint.h" |
19 | 19 | ||
20 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 20 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
21 | #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) | 21 | #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) |
22 | 22 | ||
23 | static int __perf_evsel__sample_size(u64 sample_type) | 23 | static int __perf_evsel__sample_size(u64 sample_type) |
24 | { | 24 | { |
25 | u64 mask = sample_type & PERF_SAMPLE_MASK; | 25 | u64 mask = sample_type & PERF_SAMPLE_MASK; |
26 | int size = 0; | 26 | int size = 0; |
27 | int i; | 27 | int i; |
28 | 28 | ||
29 | for (i = 0; i < 64; i++) { | 29 | for (i = 0; i < 64; i++) { |
30 | if (mask & (1ULL << i)) | 30 | if (mask & (1ULL << i)) |
31 | size++; | 31 | size++; |
32 | } | 32 | } |
33 | 33 | ||
34 | size *= sizeof(u64); | 34 | size *= sizeof(u64); |
35 | 35 | ||
36 | return size; | 36 | return size; |
37 | } | 37 | } |
38 | 38 | ||
39 | void hists__init(struct hists *hists) | 39 | void hists__init(struct hists *hists) |
40 | { | 40 | { |
41 | memset(hists, 0, sizeof(*hists)); | 41 | memset(hists, 0, sizeof(*hists)); |
42 | hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; | 42 | hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; |
43 | hists->entries_in = &hists->entries_in_array[0]; | 43 | hists->entries_in = &hists->entries_in_array[0]; |
44 | hists->entries_collapsed = RB_ROOT; | 44 | hists->entries_collapsed = RB_ROOT; |
45 | hists->entries = RB_ROOT; | 45 | hists->entries = RB_ROOT; |
46 | pthread_mutex_init(&hists->lock, NULL); | 46 | pthread_mutex_init(&hists->lock, NULL); |
47 | } | 47 | } |
48 | 48 | ||
49 | void perf_evsel__init(struct perf_evsel *evsel, | 49 | void perf_evsel__init(struct perf_evsel *evsel, |
50 | struct perf_event_attr *attr, int idx) | 50 | struct perf_event_attr *attr, int idx) |
51 | { | 51 | { |
52 | evsel->idx = idx; | 52 | evsel->idx = idx; |
53 | evsel->attr = *attr; | 53 | evsel->attr = *attr; |
54 | INIT_LIST_HEAD(&evsel->node); | 54 | INIT_LIST_HEAD(&evsel->node); |
55 | hists__init(&evsel->hists); | 55 | hists__init(&evsel->hists); |
56 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); | 56 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); |
57 | } | 57 | } |
58 | 58 | ||
59 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | 59 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) |
60 | { | 60 | { |
61 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); | 61 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); |
62 | 62 | ||
63 | if (evsel != NULL) | 63 | if (evsel != NULL) |
64 | perf_evsel__init(evsel, attr, idx); | 64 | perf_evsel__init(evsel, attr, idx); |
65 | 65 | ||
66 | return evsel; | 66 | return evsel; |
67 | } | 67 | } |
68 | 68 | ||
69 | static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { | 69 | static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { |
70 | "cycles", | 70 | "cycles", |
71 | "instructions", | 71 | "instructions", |
72 | "cache-references", | 72 | "cache-references", |
73 | "cache-misses", | 73 | "cache-misses", |
74 | "branches", | 74 | "branches", |
75 | "branch-misses", | 75 | "branch-misses", |
76 | "bus-cycles", | 76 | "bus-cycles", |
77 | "stalled-cycles-frontend", | 77 | "stalled-cycles-frontend", |
78 | "stalled-cycles-backend", | 78 | "stalled-cycles-backend", |
79 | "ref-cycles", | 79 | "ref-cycles", |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static const char *__perf_evsel__hw_name(u64 config) | 82 | static const char *__perf_evsel__hw_name(u64 config) |
83 | { | 83 | { |
84 | if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) | 84 | if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) |
85 | return perf_evsel__hw_names[config]; | 85 | return perf_evsel__hw_names[config]; |
86 | 86 | ||
87 | return "unknown-hardware"; | 87 | return "unknown-hardware"; |
88 | } | 88 | } |
89 | 89 | ||
90 | static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size) | 90 | static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size) |
91 | { | 91 | { |
92 | int colon = 0, r = 0; | 92 | int colon = 0, r = 0; |
93 | struct perf_event_attr *attr = &evsel->attr; | 93 | struct perf_event_attr *attr = &evsel->attr; |
94 | bool exclude_guest_default = false; | 94 | bool exclude_guest_default = false; |
95 | 95 | ||
96 | #define MOD_PRINT(context, mod) do { \ | 96 | #define MOD_PRINT(context, mod) do { \ |
97 | if (!attr->exclude_##context) { \ | 97 | if (!attr->exclude_##context) { \ |
98 | if (!colon) colon = ++r; \ | 98 | if (!colon) colon = ++r; \ |
99 | r += scnprintf(bf + r, size - r, "%c", mod); \ | 99 | r += scnprintf(bf + r, size - r, "%c", mod); \ |
100 | } } while(0) | 100 | } } while(0) |
101 | 101 | ||
102 | if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) { | 102 | if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) { |
103 | MOD_PRINT(kernel, 'k'); | 103 | MOD_PRINT(kernel, 'k'); |
104 | MOD_PRINT(user, 'u'); | 104 | MOD_PRINT(user, 'u'); |
105 | MOD_PRINT(hv, 'h'); | 105 | MOD_PRINT(hv, 'h'); |
106 | exclude_guest_default = true; | 106 | exclude_guest_default = true; |
107 | } | 107 | } |
108 | 108 | ||
109 | if (attr->precise_ip) { | 109 | if (attr->precise_ip) { |
110 | if (!colon) | 110 | if (!colon) |
111 | colon = ++r; | 111 | colon = ++r; |
112 | r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); | 112 | r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); |
113 | exclude_guest_default = true; | 113 | exclude_guest_default = true; |
114 | } | 114 | } |
115 | 115 | ||
116 | if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) { | 116 | if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) { |
117 | MOD_PRINT(host, 'H'); | 117 | MOD_PRINT(host, 'H'); |
118 | MOD_PRINT(guest, 'G'); | 118 | MOD_PRINT(guest, 'G'); |
119 | } | 119 | } |
120 | #undef MOD_PRINT | 120 | #undef MOD_PRINT |
121 | if (colon) | 121 | if (colon) |
122 | bf[colon - 1] = ':'; | 122 | bf[colon - 1] = ':'; |
123 | return r; | 123 | return r; |
124 | } | 124 | } |
125 | 125 | ||
126 | static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) | 126 | static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) |
127 | { | 127 | { |
128 | int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config)); | 128 | int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config)); |
129 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | 129 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); |
130 | } | 130 | } |
131 | 131 | ||
132 | static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { | 132 | static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { |
133 | "cpu-clock", | 133 | "cpu-clock", |
134 | "task-clock", | 134 | "task-clock", |
135 | "page-faults", | 135 | "page-faults", |
136 | "context-switches", | 136 | "context-switches", |
137 | "CPU-migrations", | 137 | "CPU-migrations", |
138 | "minor-faults", | 138 | "minor-faults", |
139 | "major-faults", | 139 | "major-faults", |
140 | "alignment-faults", | 140 | "alignment-faults", |
141 | "emulation-faults", | 141 | "emulation-faults", |
142 | }; | 142 | }; |
143 | 143 | ||
144 | static const char *__perf_evsel__sw_name(u64 config) | 144 | static const char *__perf_evsel__sw_name(u64 config) |
145 | { | 145 | { |
146 | if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config]) | 146 | if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config]) |
147 | return perf_evsel__sw_names[config]; | 147 | return perf_evsel__sw_names[config]; |
148 | return "unknown-software"; | 148 | return "unknown-software"; |
149 | } | 149 | } |
150 | 150 | ||
151 | static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) | 151 | static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) |
152 | { | 152 | { |
153 | int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config)); | 153 | int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config)); |
154 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | 154 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); |
155 | } | 155 | } |
156 | 156 | ||
157 | static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) | 157 | static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) |
158 | { | 158 | { |
159 | int r; | 159 | int r; |
160 | 160 | ||
161 | r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr); | 161 | r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr); |
162 | 162 | ||
163 | if (type & HW_BREAKPOINT_R) | 163 | if (type & HW_BREAKPOINT_R) |
164 | r += scnprintf(bf + r, size - r, "r"); | 164 | r += scnprintf(bf + r, size - r, "r"); |
165 | 165 | ||
166 | if (type & HW_BREAKPOINT_W) | 166 | if (type & HW_BREAKPOINT_W) |
167 | r += scnprintf(bf + r, size - r, "w"); | 167 | r += scnprintf(bf + r, size - r, "w"); |
168 | 168 | ||
169 | if (type & HW_BREAKPOINT_X) | 169 | if (type & HW_BREAKPOINT_X) |
170 | r += scnprintf(bf + r, size - r, "x"); | 170 | r += scnprintf(bf + r, size - r, "x"); |
171 | 171 | ||
172 | return r; | 172 | return r; |
173 | } | 173 | } |
174 | 174 | ||
175 | static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size) | 175 | static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size) |
176 | { | 176 | { |
177 | struct perf_event_attr *attr = &evsel->attr; | 177 | struct perf_event_attr *attr = &evsel->attr; |
178 | int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type); | 178 | int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type); |
179 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); | 179 | return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); |
180 | } | 180 | } |
181 | 181 | ||
182 | const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] | 182 | const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] |
183 | [PERF_EVSEL__MAX_ALIASES] = { | 183 | [PERF_EVSEL__MAX_ALIASES] = { |
184 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, | 184 | { "L1-dcache", "l1-d", "l1d", "L1-data", }, |
185 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, | 185 | { "L1-icache", "l1-i", "l1i", "L1-instruction", }, |
186 | { "LLC", "L2", }, | 186 | { "LLC", "L2", }, |
187 | { "dTLB", "d-tlb", "Data-TLB", }, | 187 | { "dTLB", "d-tlb", "Data-TLB", }, |
188 | { "iTLB", "i-tlb", "Instruction-TLB", }, | 188 | { "iTLB", "i-tlb", "Instruction-TLB", }, |
189 | { "branch", "branches", "bpu", "btb", "bpc", }, | 189 | { "branch", "branches", "bpu", "btb", "bpc", }, |
190 | { "node", }, | 190 | { "node", }, |
191 | }; | 191 | }; |
192 | 192 | ||
193 | const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] | 193 | const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] |
194 | [PERF_EVSEL__MAX_ALIASES] = { | 194 | [PERF_EVSEL__MAX_ALIASES] = { |
195 | { "load", "loads", "read", }, | 195 | { "load", "loads", "read", }, |
196 | { "store", "stores", "write", }, | 196 | { "store", "stores", "write", }, |
197 | { "prefetch", "prefetches", "speculative-read", "speculative-load", }, | 197 | { "prefetch", "prefetches", "speculative-read", "speculative-load", }, |
198 | }; | 198 | }; |
199 | 199 | ||
200 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] | 200 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] |
201 | [PERF_EVSEL__MAX_ALIASES] = { | 201 | [PERF_EVSEL__MAX_ALIASES] = { |
202 | { "refs", "Reference", "ops", "access", }, | 202 | { "refs", "Reference", "ops", "access", }, |
203 | { "misses", "miss", }, | 203 | { "misses", "miss", }, |
204 | }; | 204 | }; |
205 | 205 | ||
206 | #define C(x) PERF_COUNT_HW_CACHE_##x | 206 | #define C(x) PERF_COUNT_HW_CACHE_##x |
207 | #define CACHE_READ (1 << C(OP_READ)) | 207 | #define CACHE_READ (1 << C(OP_READ)) |
208 | #define CACHE_WRITE (1 << C(OP_WRITE)) | 208 | #define CACHE_WRITE (1 << C(OP_WRITE)) |
209 | #define CACHE_PREFETCH (1 << C(OP_PREFETCH)) | 209 | #define CACHE_PREFETCH (1 << C(OP_PREFETCH)) |
210 | #define COP(x) (1 << x) | 210 | #define COP(x) (1 << x) |
211 | 211 | ||
212 | /* | 212 | /* |
213 | * cache operartion stat | 213 | * cache operartion stat |
214 | * L1I : Read and prefetch only | 214 | * L1I : Read and prefetch only |
215 | * ITLB and BPU : Read-only | 215 | * ITLB and BPU : Read-only |
216 | */ | 216 | */ |
217 | static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = { | 217 | static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = { |
218 | [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | 218 | [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), |
219 | [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), | 219 | [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), |
220 | [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | 220 | [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), |
221 | [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | 221 | [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), |
222 | [C(ITLB)] = (CACHE_READ), | 222 | [C(ITLB)] = (CACHE_READ), |
223 | [C(BPU)] = (CACHE_READ), | 223 | [C(BPU)] = (CACHE_READ), |
224 | [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), | 224 | [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), |
225 | }; | 225 | }; |
226 | 226 | ||
227 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op) | 227 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op) |
228 | { | 228 | { |
229 | if (perf_evsel__hw_cache_stat[type] & COP(op)) | 229 | if (perf_evsel__hw_cache_stat[type] & COP(op)) |
230 | return true; /* valid */ | 230 | return true; /* valid */ |
231 | else | 231 | else |
232 | return false; /* invalid */ | 232 | return false; /* invalid */ |
233 | } | 233 | } |
234 | 234 | ||
235 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | 235 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, |
236 | char *bf, size_t size) | 236 | char *bf, size_t size) |
237 | { | 237 | { |
238 | if (result) { | 238 | if (result) { |
239 | return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0], | 239 | return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0], |
240 | perf_evsel__hw_cache_op[op][0], | 240 | perf_evsel__hw_cache_op[op][0], |
241 | perf_evsel__hw_cache_result[result][0]); | 241 | perf_evsel__hw_cache_result[result][0]); |
242 | } | 242 | } |
243 | 243 | ||
244 | return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0], | 244 | return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0], |
245 | perf_evsel__hw_cache_op[op][1]); | 245 | perf_evsel__hw_cache_op[op][1]); |
246 | } | 246 | } |
247 | 247 | ||
248 | static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size) | 248 | static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size) |
249 | { | 249 | { |
250 | u8 op, result, type = (config >> 0) & 0xff; | 250 | u8 op, result, type = (config >> 0) & 0xff; |
251 | const char *err = "unknown-ext-hardware-cache-type"; | 251 | const char *err = "unknown-ext-hardware-cache-type"; |
252 | 252 | ||
253 | if (type > PERF_COUNT_HW_CACHE_MAX) | 253 | if (type > PERF_COUNT_HW_CACHE_MAX) |
254 | goto out_err; | 254 | goto out_err; |
255 | 255 | ||
256 | op = (config >> 8) & 0xff; | 256 | op = (config >> 8) & 0xff; |
257 | err = "unknown-ext-hardware-cache-op"; | 257 | err = "unknown-ext-hardware-cache-op"; |
258 | if (op > PERF_COUNT_HW_CACHE_OP_MAX) | 258 | if (op > PERF_COUNT_HW_CACHE_OP_MAX) |
259 | goto out_err; | 259 | goto out_err; |
260 | 260 | ||
261 | result = (config >> 16) & 0xff; | 261 | result = (config >> 16) & 0xff; |
262 | err = "unknown-ext-hardware-cache-result"; | 262 | err = "unknown-ext-hardware-cache-result"; |
263 | if (result > PERF_COUNT_HW_CACHE_RESULT_MAX) | 263 | if (result > PERF_COUNT_HW_CACHE_RESULT_MAX) |
264 | goto out_err; | 264 | goto out_err; |
265 | 265 | ||
266 | err = "invalid-cache"; | 266 | err = "invalid-cache"; |
267 | if (!perf_evsel__is_cache_op_valid(type, op)) | 267 | if (!perf_evsel__is_cache_op_valid(type, op)) |
268 | goto out_err; | 268 | goto out_err; |
269 | 269 | ||
270 | return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size); | 270 | return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size); |
271 | out_err: | 271 | out_err: |
272 | return scnprintf(bf, size, "%s", err); | 272 | return scnprintf(bf, size, "%s", err); |
273 | } | 273 | } |
274 | 274 | ||
275 | static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size) | 275 | static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size) |
276 | { | 276 | { |
277 | int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size); | 277 | int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size); |
278 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); | 278 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); |
279 | } | 279 | } |
280 | 280 | ||
281 | static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size) | 281 | static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size) |
282 | { | 282 | { |
283 | int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); | 283 | int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); |
284 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); | 284 | return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); |
285 | } | 285 | } |
286 | 286 | ||
287 | const char *perf_evsel__name(struct perf_evsel *evsel) | 287 | const char *perf_evsel__name(struct perf_evsel *evsel) |
288 | { | 288 | { |
289 | char bf[128]; | 289 | char bf[128]; |
290 | 290 | ||
291 | if (evsel->name) | 291 | if (evsel->name) |
292 | return evsel->name; | 292 | return evsel->name; |
293 | 293 | ||
294 | switch (evsel->attr.type) { | 294 | switch (evsel->attr.type) { |
295 | case PERF_TYPE_RAW: | 295 | case PERF_TYPE_RAW: |
296 | perf_evsel__raw_name(evsel, bf, sizeof(bf)); | 296 | perf_evsel__raw_name(evsel, bf, sizeof(bf)); |
297 | break; | 297 | break; |
298 | 298 | ||
299 | case PERF_TYPE_HARDWARE: | 299 | case PERF_TYPE_HARDWARE: |
300 | perf_evsel__hw_name(evsel, bf, sizeof(bf)); | 300 | perf_evsel__hw_name(evsel, bf, sizeof(bf)); |
301 | break; | 301 | break; |
302 | 302 | ||
303 | case PERF_TYPE_HW_CACHE: | 303 | case PERF_TYPE_HW_CACHE: |
304 | perf_evsel__hw_cache_name(evsel, bf, sizeof(bf)); | 304 | perf_evsel__hw_cache_name(evsel, bf, sizeof(bf)); |
305 | break; | 305 | break; |
306 | 306 | ||
307 | case PERF_TYPE_SOFTWARE: | 307 | case PERF_TYPE_SOFTWARE: |
308 | perf_evsel__sw_name(evsel, bf, sizeof(bf)); | 308 | perf_evsel__sw_name(evsel, bf, sizeof(bf)); |
309 | break; | 309 | break; |
310 | 310 | ||
311 | case PERF_TYPE_TRACEPOINT: | 311 | case PERF_TYPE_TRACEPOINT: |
312 | scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint"); | 312 | scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint"); |
313 | break; | 313 | break; |
314 | 314 | ||
315 | case PERF_TYPE_BREAKPOINT: | 315 | case PERF_TYPE_BREAKPOINT: |
316 | perf_evsel__bp_name(evsel, bf, sizeof(bf)); | 316 | perf_evsel__bp_name(evsel, bf, sizeof(bf)); |
317 | break; | 317 | break; |
318 | 318 | ||
319 | default: | 319 | default: |
320 | scnprintf(bf, sizeof(bf), "%s", "unknown attr type"); | 320 | scnprintf(bf, sizeof(bf), "%s", "unknown attr type"); |
321 | break; | 321 | break; |
322 | } | 322 | } |
323 | 323 | ||
324 | evsel->name = strdup(bf); | 324 | evsel->name = strdup(bf); |
325 | 325 | ||
326 | return evsel->name ?: "unknown"; | 326 | return evsel->name ?: "unknown"; |
327 | } | 327 | } |
328 | 328 | ||
329 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, | 329 | void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, |
330 | struct perf_evsel *first) | 330 | struct perf_evsel *first) |
331 | { | 331 | { |
332 | struct perf_event_attr *attr = &evsel->attr; | 332 | struct perf_event_attr *attr = &evsel->attr; |
333 | int track = !evsel->idx; /* only the first counter needs these */ | 333 | int track = !evsel->idx; /* only the first counter needs these */ |
334 | 334 | ||
335 | attr->disabled = 1; | 335 | attr->disabled = 1; |
336 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; | 336 | attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; |
337 | attr->inherit = !opts->no_inherit; | 337 | attr->inherit = !opts->no_inherit; |
338 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 338 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
339 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 339 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
340 | PERF_FORMAT_ID; | 340 | PERF_FORMAT_ID; |
341 | 341 | ||
342 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 342 | attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
343 | 343 | ||
344 | /* | 344 | /* |
345 | * We default some events to a 1 default interval. But keep | 345 | * We default some events to a 1 default interval. But keep |
346 | * it a weak assumption overridable by the user. | 346 | * it a weak assumption overridable by the user. |
347 | */ | 347 | */ |
348 | if (!attr->sample_period || (opts->user_freq != UINT_MAX && | 348 | if (!attr->sample_period || (opts->user_freq != UINT_MAX && |
349 | opts->user_interval != ULLONG_MAX)) { | 349 | opts->user_interval != ULLONG_MAX)) { |
350 | if (opts->freq) { | 350 | if (opts->freq) { |
351 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 351 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
352 | attr->freq = 1; | 352 | attr->freq = 1; |
353 | attr->sample_freq = opts->freq; | 353 | attr->sample_freq = opts->freq; |
354 | } else { | 354 | } else { |
355 | attr->sample_period = opts->default_interval; | 355 | attr->sample_period = opts->default_interval; |
356 | } | 356 | } |
357 | } | 357 | } |
358 | 358 | ||
359 | if (opts->no_samples) | 359 | if (opts->no_samples) |
360 | attr->sample_freq = 0; | 360 | attr->sample_freq = 0; |
361 | 361 | ||
362 | if (opts->inherit_stat) | 362 | if (opts->inherit_stat) |
363 | attr->inherit_stat = 1; | 363 | attr->inherit_stat = 1; |
364 | 364 | ||
365 | if (opts->sample_address) { | 365 | if (opts->sample_address) { |
366 | attr->sample_type |= PERF_SAMPLE_ADDR; | 366 | attr->sample_type |= PERF_SAMPLE_ADDR; |
367 | attr->mmap_data = track; | 367 | attr->mmap_data = track; |
368 | } | 368 | } |
369 | 369 | ||
370 | if (opts->call_graph) | 370 | if (opts->call_graph) |
371 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; | 371 | attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
372 | 372 | ||
373 | if (perf_target__has_cpu(&opts->target)) | 373 | if (perf_target__has_cpu(&opts->target)) |
374 | attr->sample_type |= PERF_SAMPLE_CPU; | 374 | attr->sample_type |= PERF_SAMPLE_CPU; |
375 | 375 | ||
376 | if (opts->period) | 376 | if (opts->period) |
377 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 377 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
378 | 378 | ||
379 | if (!opts->sample_id_all_missing && | 379 | if (!opts->sample_id_all_missing && |
380 | (opts->sample_time || !opts->no_inherit || | 380 | (opts->sample_time || !opts->no_inherit || |
381 | perf_target__has_cpu(&opts->target))) | 381 | perf_target__has_cpu(&opts->target))) |
382 | attr->sample_type |= PERF_SAMPLE_TIME; | 382 | attr->sample_type |= PERF_SAMPLE_TIME; |
383 | 383 | ||
384 | if (opts->raw_samples) { | 384 | if (opts->raw_samples) { |
385 | attr->sample_type |= PERF_SAMPLE_TIME; | 385 | attr->sample_type |= PERF_SAMPLE_TIME; |
386 | attr->sample_type |= PERF_SAMPLE_RAW; | 386 | attr->sample_type |= PERF_SAMPLE_RAW; |
387 | attr->sample_type |= PERF_SAMPLE_CPU; | 387 | attr->sample_type |= PERF_SAMPLE_CPU; |
388 | } | 388 | } |
389 | 389 | ||
390 | if (opts->no_delay) { | 390 | if (opts->no_delay) { |
391 | attr->watermark = 0; | 391 | attr->watermark = 0; |
392 | attr->wakeup_events = 1; | 392 | attr->wakeup_events = 1; |
393 | } | 393 | } |
394 | if (opts->branch_stack) { | 394 | if (opts->branch_stack) { |
395 | attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; | 395 | attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; |
396 | attr->branch_sample_type = opts->branch_stack; | 396 | attr->branch_sample_type = opts->branch_stack; |
397 | } | 397 | } |
398 | 398 | ||
399 | attr->mmap = track; | 399 | attr->mmap = track; |
400 | attr->comm = track; | 400 | attr->comm = track; |
401 | 401 | ||
402 | if (perf_target__none(&opts->target) && | 402 | if (perf_target__none(&opts->target) && |
403 | (!opts->group || evsel == first)) { | 403 | (!opts->group || evsel == first)) { |
404 | attr->enable_on_exec = 1; | 404 | attr->enable_on_exec = 1; |
405 | } | 405 | } |
406 | } | 406 | } |
407 | 407 | ||
408 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 408 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
409 | { | 409 | { |
410 | int cpu, thread; | 410 | int cpu, thread; |
411 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); | 411 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); |
412 | 412 | ||
413 | if (evsel->fd) { | 413 | if (evsel->fd) { |
414 | for (cpu = 0; cpu < ncpus; cpu++) { | 414 | for (cpu = 0; cpu < ncpus; cpu++) { |
415 | for (thread = 0; thread < nthreads; thread++) { | 415 | for (thread = 0; thread < nthreads; thread++) { |
416 | FD(evsel, cpu, thread) = -1; | 416 | FD(evsel, cpu, thread) = -1; |
417 | } | 417 | } |
418 | } | 418 | } |
419 | } | 419 | } |
420 | 420 | ||
421 | return evsel->fd != NULL ? 0 : -ENOMEM; | 421 | return evsel->fd != NULL ? 0 : -ENOMEM; |
422 | } | 422 | } |
423 | 423 | ||
424 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | 424 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) |
425 | { | 425 | { |
426 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); | 426 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); |
427 | if (evsel->sample_id == NULL) | 427 | if (evsel->sample_id == NULL) |
428 | return -ENOMEM; | 428 | return -ENOMEM; |
429 | 429 | ||
430 | evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); | 430 | evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); |
431 | if (evsel->id == NULL) { | 431 | if (evsel->id == NULL) { |
432 | xyarray__delete(evsel->sample_id); | 432 | xyarray__delete(evsel->sample_id); |
433 | evsel->sample_id = NULL; | 433 | evsel->sample_id = NULL; |
434 | return -ENOMEM; | 434 | return -ENOMEM; |
435 | } | 435 | } |
436 | 436 | ||
437 | return 0; | 437 | return 0; |
438 | } | 438 | } |
439 | 439 | ||
440 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | 440 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) |
441 | { | 441 | { |
442 | evsel->counts = zalloc((sizeof(*evsel->counts) + | 442 | evsel->counts = zalloc((sizeof(*evsel->counts) + |
443 | (ncpus * sizeof(struct perf_counts_values)))); | 443 | (ncpus * sizeof(struct perf_counts_values)))); |
444 | return evsel->counts != NULL ? 0 : -ENOMEM; | 444 | return evsel->counts != NULL ? 0 : -ENOMEM; |
445 | } | 445 | } |
446 | 446 | ||
447 | void perf_evsel__free_fd(struct perf_evsel *evsel) | 447 | void perf_evsel__free_fd(struct perf_evsel *evsel) |
448 | { | 448 | { |
449 | xyarray__delete(evsel->fd); | 449 | xyarray__delete(evsel->fd); |
450 | evsel->fd = NULL; | 450 | evsel->fd = NULL; |
451 | } | 451 | } |
452 | 452 | ||
453 | void perf_evsel__free_id(struct perf_evsel *evsel) | 453 | void perf_evsel__free_id(struct perf_evsel *evsel) |
454 | { | 454 | { |
455 | xyarray__delete(evsel->sample_id); | 455 | xyarray__delete(evsel->sample_id); |
456 | evsel->sample_id = NULL; | 456 | evsel->sample_id = NULL; |
457 | free(evsel->id); | 457 | free(evsel->id); |
458 | evsel->id = NULL; | 458 | evsel->id = NULL; |
459 | } | 459 | } |
460 | 460 | ||
461 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 461 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
462 | { | 462 | { |
463 | int cpu, thread; | 463 | int cpu, thread; |
464 | 464 | ||
465 | for (cpu = 0; cpu < ncpus; cpu++) | 465 | for (cpu = 0; cpu < ncpus; cpu++) |
466 | for (thread = 0; thread < nthreads; ++thread) { | 466 | for (thread = 0; thread < nthreads; ++thread) { |
467 | close(FD(evsel, cpu, thread)); | 467 | close(FD(evsel, cpu, thread)); |
468 | FD(evsel, cpu, thread) = -1; | 468 | FD(evsel, cpu, thread) = -1; |
469 | } | 469 | } |
470 | } | 470 | } |
471 | 471 | ||
472 | void perf_evsel__exit(struct perf_evsel *evsel) | 472 | void perf_evsel__exit(struct perf_evsel *evsel) |
473 | { | 473 | { |
474 | assert(list_empty(&evsel->node)); | 474 | assert(list_empty(&evsel->node)); |
475 | xyarray__delete(evsel->fd); | 475 | xyarray__delete(evsel->fd); |
476 | xyarray__delete(evsel->sample_id); | 476 | xyarray__delete(evsel->sample_id); |
477 | free(evsel->id); | 477 | free(evsel->id); |
478 | } | 478 | } |
479 | 479 | ||
480 | void perf_evsel__delete(struct perf_evsel *evsel) | 480 | void perf_evsel__delete(struct perf_evsel *evsel) |
481 | { | 481 | { |
482 | perf_evsel__exit(evsel); | 482 | perf_evsel__exit(evsel); |
483 | close_cgroup(evsel->cgrp); | 483 | close_cgroup(evsel->cgrp); |
484 | free(evsel->name); | 484 | free(evsel->name); |
485 | free(evsel); | 485 | free(evsel); |
486 | } | 486 | } |
487 | 487 | ||
488 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 488 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
489 | int cpu, int thread, bool scale) | 489 | int cpu, int thread, bool scale) |
490 | { | 490 | { |
491 | struct perf_counts_values count; | 491 | struct perf_counts_values count; |
492 | size_t nv = scale ? 3 : 1; | 492 | size_t nv = scale ? 3 : 1; |
493 | 493 | ||
494 | if (FD(evsel, cpu, thread) < 0) | 494 | if (FD(evsel, cpu, thread) < 0) |
495 | return -EINVAL; | 495 | return -EINVAL; |
496 | 496 | ||
497 | if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0) | 497 | if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0) |
498 | return -ENOMEM; | 498 | return -ENOMEM; |
499 | 499 | ||
500 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) | 500 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) |
501 | return -errno; | 501 | return -errno; |
502 | 502 | ||
503 | if (scale) { | 503 | if (scale) { |
504 | if (count.run == 0) | 504 | if (count.run == 0) |
505 | count.val = 0; | 505 | count.val = 0; |
506 | else if (count.run < count.ena) | 506 | else if (count.run < count.ena) |
507 | count.val = (u64)((double)count.val * count.ena / count.run + 0.5); | 507 | count.val = (u64)((double)count.val * count.ena / count.run + 0.5); |
508 | } else | 508 | } else |
509 | count.ena = count.run = 0; | 509 | count.ena = count.run = 0; |
510 | 510 | ||
511 | evsel->counts->cpu[cpu] = count; | 511 | evsel->counts->cpu[cpu] = count; |
512 | return 0; | 512 | return 0; |
513 | } | 513 | } |
514 | 514 | ||
515 | int __perf_evsel__read(struct perf_evsel *evsel, | 515 | int __perf_evsel__read(struct perf_evsel *evsel, |
516 | int ncpus, int nthreads, bool scale) | 516 | int ncpus, int nthreads, bool scale) |
517 | { | 517 | { |
518 | size_t nv = scale ? 3 : 1; | 518 | size_t nv = scale ? 3 : 1; |
519 | int cpu, thread; | 519 | int cpu, thread; |
520 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; | 520 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; |
521 | 521 | ||
522 | aggr->val = aggr->ena = aggr->run = 0; | 522 | aggr->val = aggr->ena = aggr->run = 0; |
523 | 523 | ||
524 | for (cpu = 0; cpu < ncpus; cpu++) { | 524 | for (cpu = 0; cpu < ncpus; cpu++) { |
525 | for (thread = 0; thread < nthreads; thread++) { | 525 | for (thread = 0; thread < nthreads; thread++) { |
526 | if (FD(evsel, cpu, thread) < 0) | 526 | if (FD(evsel, cpu, thread) < 0) |
527 | continue; | 527 | continue; |
528 | 528 | ||
529 | if (readn(FD(evsel, cpu, thread), | 529 | if (readn(FD(evsel, cpu, thread), |
530 | &count, nv * sizeof(u64)) < 0) | 530 | &count, nv * sizeof(u64)) < 0) |
531 | return -errno; | 531 | return -errno; |
532 | 532 | ||
533 | aggr->val += count.val; | 533 | aggr->val += count.val; |
534 | if (scale) { | 534 | if (scale) { |
535 | aggr->ena += count.ena; | 535 | aggr->ena += count.ena; |
536 | aggr->run += count.run; | 536 | aggr->run += count.run; |
537 | } | 537 | } |
538 | } | 538 | } |
539 | } | 539 | } |
540 | 540 | ||
541 | evsel->counts->scaled = 0; | 541 | evsel->counts->scaled = 0; |
542 | if (scale) { | 542 | if (scale) { |
543 | if (aggr->run == 0) { | 543 | if (aggr->run == 0) { |
544 | evsel->counts->scaled = -1; | 544 | evsel->counts->scaled = -1; |
545 | aggr->val = 0; | 545 | aggr->val = 0; |
546 | return 0; | 546 | return 0; |
547 | } | 547 | } |
548 | 548 | ||
549 | if (aggr->run < aggr->ena) { | 549 | if (aggr->run < aggr->ena) { |
550 | evsel->counts->scaled = 1; | 550 | evsel->counts->scaled = 1; |
551 | aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5); | 551 | aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5); |
552 | } | 552 | } |
553 | } else | 553 | } else |
554 | aggr->ena = aggr->run = 0; | 554 | aggr->ena = aggr->run = 0; |
555 | 555 | ||
556 | return 0; | 556 | return 0; |
557 | } | 557 | } |
558 | 558 | ||
559 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 559 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
560 | struct thread_map *threads, bool group, | 560 | struct thread_map *threads, bool group, |
561 | struct xyarray *group_fds) | 561 | struct xyarray *group_fds) |
562 | { | 562 | { |
563 | int cpu, thread; | 563 | int cpu, thread; |
564 | unsigned long flags = 0; | 564 | unsigned long flags = 0; |
565 | int pid = -1, err; | 565 | int pid = -1, err; |
566 | 566 | ||
567 | if (evsel->fd == NULL && | 567 | if (evsel->fd == NULL && |
568 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | 568 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) |
569 | return -ENOMEM; | 569 | return -ENOMEM; |
570 | 570 | ||
571 | if (evsel->cgrp) { | 571 | if (evsel->cgrp) { |
572 | flags = PERF_FLAG_PID_CGROUP; | 572 | flags = PERF_FLAG_PID_CGROUP; |
573 | pid = evsel->cgrp->fd; | 573 | pid = evsel->cgrp->fd; |
574 | } | 574 | } |
575 | 575 | ||
576 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 576 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
577 | int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1; | 577 | int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1; |
578 | 578 | ||
579 | for (thread = 0; thread < threads->nr; thread++) { | 579 | for (thread = 0; thread < threads->nr; thread++) { |
580 | 580 | ||
581 | if (!evsel->cgrp) | 581 | if (!evsel->cgrp) |
582 | pid = threads->map[thread]; | 582 | pid = threads->map[thread]; |
583 | 583 | ||
584 | FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, | 584 | FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, |
585 | pid, | 585 | pid, |
586 | cpus->map[cpu], | 586 | cpus->map[cpu], |
587 | group_fd, flags); | 587 | group_fd, flags); |
588 | if (FD(evsel, cpu, thread) < 0) { | 588 | if (FD(evsel, cpu, thread) < 0) { |
589 | err = -errno; | 589 | err = -errno; |
590 | goto out_close; | 590 | goto out_close; |
591 | } | 591 | } |
592 | 592 | ||
593 | if (group && group_fd == -1) | 593 | if (group && group_fd == -1) |
594 | group_fd = FD(evsel, cpu, thread); | 594 | group_fd = FD(evsel, cpu, thread); |
595 | } | 595 | } |
596 | } | 596 | } |
597 | 597 | ||
598 | return 0; | 598 | return 0; |
599 | 599 | ||
600 | out_close: | 600 | out_close: |
601 | do { | 601 | do { |
602 | while (--thread >= 0) { | 602 | while (--thread >= 0) { |
603 | close(FD(evsel, cpu, thread)); | 603 | close(FD(evsel, cpu, thread)); |
604 | FD(evsel, cpu, thread) = -1; | 604 | FD(evsel, cpu, thread) = -1; |
605 | } | 605 | } |
606 | thread = threads->nr; | 606 | thread = threads->nr; |
607 | } while (--cpu >= 0); | 607 | } while (--cpu >= 0); |
608 | return err; | 608 | return err; |
609 | } | 609 | } |
610 | 610 | ||
611 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | 611 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) |
612 | { | 612 | { |
613 | if (evsel->fd == NULL) | 613 | if (evsel->fd == NULL) |
614 | return; | 614 | return; |
615 | 615 | ||
616 | perf_evsel__close_fd(evsel, ncpus, nthreads); | 616 | perf_evsel__close_fd(evsel, ncpus, nthreads); |
617 | perf_evsel__free_fd(evsel); | 617 | perf_evsel__free_fd(evsel); |
618 | evsel->fd = NULL; | 618 | evsel->fd = NULL; |
619 | } | 619 | } |
620 | 620 | ||
621 | static struct { | 621 | static struct { |
622 | struct cpu_map map; | 622 | struct cpu_map map; |
623 | int cpus[1]; | 623 | int cpus[1]; |
624 | } empty_cpu_map = { | 624 | } empty_cpu_map = { |
625 | .map.nr = 1, | 625 | .map.nr = 1, |
626 | .cpus = { -1, }, | 626 | .cpus = { -1, }, |
627 | }; | 627 | }; |
628 | 628 | ||
629 | static struct { | 629 | static struct { |
630 | struct thread_map map; | 630 | struct thread_map map; |
631 | int threads[1]; | 631 | int threads[1]; |
632 | } empty_thread_map = { | 632 | } empty_thread_map = { |
633 | .map.nr = 1, | 633 | .map.nr = 1, |
634 | .threads = { -1, }, | 634 | .threads = { -1, }, |
635 | }; | 635 | }; |
636 | 636 | ||
637 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 637 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
638 | struct thread_map *threads, bool group, | 638 | struct thread_map *threads, bool group, |
639 | struct xyarray *group_fd) | 639 | struct xyarray *group_fd) |
640 | { | 640 | { |
641 | if (cpus == NULL) { | 641 | if (cpus == NULL) { |
642 | /* Work around old compiler warnings about strict aliasing */ | 642 | /* Work around old compiler warnings about strict aliasing */ |
643 | cpus = &empty_cpu_map.map; | 643 | cpus = &empty_cpu_map.map; |
644 | } | 644 | } |
645 | 645 | ||
646 | if (threads == NULL) | 646 | if (threads == NULL) |
647 | threads = &empty_thread_map.map; | 647 | threads = &empty_thread_map.map; |
648 | 648 | ||
649 | return __perf_evsel__open(evsel, cpus, threads, group, group_fd); | 649 | return __perf_evsel__open(evsel, cpus, threads, group, group_fd); |
650 | } | 650 | } |
651 | 651 | ||
652 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 652 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
653 | struct cpu_map *cpus, bool group, | 653 | struct cpu_map *cpus, bool group, |
654 | struct xyarray *group_fd) | 654 | struct xyarray *group_fd) |
655 | { | 655 | { |
656 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, | 656 | return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, |
657 | group_fd); | 657 | group_fd); |
658 | } | 658 | } |
659 | 659 | ||
660 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 660 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
661 | struct thread_map *threads, bool group, | 661 | struct thread_map *threads, bool group, |
662 | struct xyarray *group_fd) | 662 | struct xyarray *group_fd) |
663 | { | 663 | { |
664 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, | 664 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, |
665 | group_fd); | 665 | group_fd); |
666 | } | 666 | } |
667 | 667 | ||
668 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | 668 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, |
669 | struct perf_sample *sample, | 669 | struct perf_sample *sample, |
670 | bool swapped) | 670 | bool swapped) |
671 | { | 671 | { |
672 | const u64 *array = event->sample.array; | 672 | const u64 *array = event->sample.array; |
673 | union u64_swap u; | 673 | union u64_swap u; |
674 | 674 | ||
675 | array += ((event->header.size - | 675 | array += ((event->header.size - |
676 | sizeof(event->header)) / sizeof(u64)) - 1; | 676 | sizeof(event->header)) / sizeof(u64)) - 1; |
677 | 677 | ||
678 | if (type & PERF_SAMPLE_CPU) { | 678 | if (type & PERF_SAMPLE_CPU) { |
679 | u.val64 = *array; | 679 | u.val64 = *array; |
680 | if (swapped) { | 680 | if (swapped) { |
681 | /* undo swap of u64, then swap on individual u32s */ | 681 | /* undo swap of u64, then swap on individual u32s */ |
682 | u.val64 = bswap_64(u.val64); | 682 | u.val64 = bswap_64(u.val64); |
683 | u.val32[0] = bswap_32(u.val32[0]); | 683 | u.val32[0] = bswap_32(u.val32[0]); |
684 | } | 684 | } |
685 | 685 | ||
686 | sample->cpu = u.val32[0]; | 686 | sample->cpu = u.val32[0]; |
687 | array--; | 687 | array--; |
688 | } | 688 | } |
689 | 689 | ||
690 | if (type & PERF_SAMPLE_STREAM_ID) { | 690 | if (type & PERF_SAMPLE_STREAM_ID) { |
691 | sample->stream_id = *array; | 691 | sample->stream_id = *array; |
692 | array--; | 692 | array--; |
693 | } | 693 | } |
694 | 694 | ||
695 | if (type & PERF_SAMPLE_ID) { | 695 | if (type & PERF_SAMPLE_ID) { |
696 | sample->id = *array; | 696 | sample->id = *array; |
697 | array--; | 697 | array--; |
698 | } | 698 | } |
699 | 699 | ||
700 | if (type & PERF_SAMPLE_TIME) { | 700 | if (type & PERF_SAMPLE_TIME) { |
701 | sample->time = *array; | 701 | sample->time = *array; |
702 | array--; | 702 | array--; |
703 | } | 703 | } |
704 | 704 | ||
705 | if (type & PERF_SAMPLE_TID) { | 705 | if (type & PERF_SAMPLE_TID) { |
706 | u.val64 = *array; | 706 | u.val64 = *array; |
707 | if (swapped) { | 707 | if (swapped) { |
708 | /* undo swap of u64, then swap on individual u32s */ | 708 | /* undo swap of u64, then swap on individual u32s */ |
709 | u.val64 = bswap_64(u.val64); | 709 | u.val64 = bswap_64(u.val64); |
710 | u.val32[0] = bswap_32(u.val32[0]); | 710 | u.val32[0] = bswap_32(u.val32[0]); |
711 | u.val32[1] = bswap_32(u.val32[1]); | 711 | u.val32[1] = bswap_32(u.val32[1]); |
712 | } | 712 | } |
713 | 713 | ||
714 | sample->pid = u.val32[0]; | 714 | sample->pid = u.val32[0]; |
715 | sample->tid = u.val32[1]; | 715 | sample->tid = u.val32[1]; |
716 | } | 716 | } |
717 | 717 | ||
718 | return 0; | 718 | return 0; |
719 | } | 719 | } |
720 | 720 | ||
721 | static bool sample_overlap(const union perf_event *event, | 721 | static bool sample_overlap(const union perf_event *event, |
722 | const void *offset, u64 size) | 722 | const void *offset, u64 size) |
723 | { | 723 | { |
724 | const void *base = event; | 724 | const void *base = event; |
725 | 725 | ||
726 | if (offset + size > base + event->header.size) | 726 | if (offset + size > base + event->header.size) |
727 | return true; | 727 | return true; |
728 | 728 | ||
729 | return false; | 729 | return false; |
730 | } | 730 | } |
731 | 731 | ||
732 | int perf_event__parse_sample(const union perf_event *event, u64 type, | 732 | int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, |
733 | int sample_size, bool sample_id_all, | ||
734 | struct perf_sample *data, bool swapped) | 733 | struct perf_sample *data, bool swapped) |
735 | { | 734 | { |
735 | u64 type = evsel->attr.sample_type; | ||
736 | const u64 *array; | 736 | const u64 *array; |
737 | 737 | ||
738 | /* | 738 | /* |
739 | * used for cross-endian analysis. See git commit 65014ab3 | 739 | * used for cross-endian analysis. See git commit 65014ab3 |
740 | * for why this goofiness is needed. | 740 | * for why this goofiness is needed. |
741 | */ | 741 | */ |
742 | union u64_swap u; | 742 | union u64_swap u; |
743 | 743 | ||
744 | memset(data, 0, sizeof(*data)); | 744 | memset(data, 0, sizeof(*data)); |
745 | data->cpu = data->pid = data->tid = -1; | 745 | data->cpu = data->pid = data->tid = -1; |
746 | data->stream_id = data->id = data->time = -1ULL; | 746 | data->stream_id = data->id = data->time = -1ULL; |
747 | data->period = 1; | 747 | data->period = 1; |
748 | 748 | ||
749 | if (event->header.type != PERF_RECORD_SAMPLE) { | 749 | if (event->header.type != PERF_RECORD_SAMPLE) { |
750 | if (!sample_id_all) | 750 | if (!evsel->attr.sample_id_all) |
751 | return 0; | 751 | return 0; |
752 | return perf_event__parse_id_sample(event, type, data, swapped); | 752 | return perf_event__parse_id_sample(event, type, data, swapped); |
753 | } | 753 | } |
754 | 754 | ||
755 | array = event->sample.array; | 755 | array = event->sample.array; |
756 | 756 | ||
757 | if (sample_size + sizeof(event->header) > event->header.size) | 757 | if (evsel->sample_size + sizeof(event->header) > event->header.size) |
758 | return -EFAULT; | 758 | return -EFAULT; |
759 | 759 | ||
760 | if (type & PERF_SAMPLE_IP) { | 760 | if (type & PERF_SAMPLE_IP) { |
761 | data->ip = event->ip.ip; | 761 | data->ip = event->ip.ip; |
762 | array++; | 762 | array++; |
763 | } | 763 | } |
764 | 764 | ||
765 | if (type & PERF_SAMPLE_TID) { | 765 | if (type & PERF_SAMPLE_TID) { |
766 | u.val64 = *array; | 766 | u.val64 = *array; |
767 | if (swapped) { | 767 | if (swapped) { |
768 | /* undo swap of u64, then swap on individual u32s */ | 768 | /* undo swap of u64, then swap on individual u32s */ |
769 | u.val64 = bswap_64(u.val64); | 769 | u.val64 = bswap_64(u.val64); |
770 | u.val32[0] = bswap_32(u.val32[0]); | 770 | u.val32[0] = bswap_32(u.val32[0]); |
771 | u.val32[1] = bswap_32(u.val32[1]); | 771 | u.val32[1] = bswap_32(u.val32[1]); |
772 | } | 772 | } |
773 | 773 | ||
774 | data->pid = u.val32[0]; | 774 | data->pid = u.val32[0]; |
775 | data->tid = u.val32[1]; | 775 | data->tid = u.val32[1]; |
776 | array++; | 776 | array++; |
777 | } | 777 | } |
778 | 778 | ||
779 | if (type & PERF_SAMPLE_TIME) { | 779 | if (type & PERF_SAMPLE_TIME) { |
780 | data->time = *array; | 780 | data->time = *array; |
781 | array++; | 781 | array++; |
782 | } | 782 | } |
783 | 783 | ||
784 | data->addr = 0; | 784 | data->addr = 0; |
785 | if (type & PERF_SAMPLE_ADDR) { | 785 | if (type & PERF_SAMPLE_ADDR) { |
786 | data->addr = *array; | 786 | data->addr = *array; |
787 | array++; | 787 | array++; |
788 | } | 788 | } |
789 | 789 | ||
790 | data->id = -1ULL; | 790 | data->id = -1ULL; |
791 | if (type & PERF_SAMPLE_ID) { | 791 | if (type & PERF_SAMPLE_ID) { |
792 | data->id = *array; | 792 | data->id = *array; |
793 | array++; | 793 | array++; |
794 | } | 794 | } |
795 | 795 | ||
796 | if (type & PERF_SAMPLE_STREAM_ID) { | 796 | if (type & PERF_SAMPLE_STREAM_ID) { |
797 | data->stream_id = *array; | 797 | data->stream_id = *array; |
798 | array++; | 798 | array++; |
799 | } | 799 | } |
800 | 800 | ||
801 | if (type & PERF_SAMPLE_CPU) { | 801 | if (type & PERF_SAMPLE_CPU) { |
802 | 802 | ||
803 | u.val64 = *array; | 803 | u.val64 = *array; |
804 | if (swapped) { | 804 | if (swapped) { |
805 | /* undo swap of u64, then swap on individual u32s */ | 805 | /* undo swap of u64, then swap on individual u32s */ |
806 | u.val64 = bswap_64(u.val64); | 806 | u.val64 = bswap_64(u.val64); |
807 | u.val32[0] = bswap_32(u.val32[0]); | 807 | u.val32[0] = bswap_32(u.val32[0]); |
808 | } | 808 | } |
809 | 809 | ||
810 | data->cpu = u.val32[0]; | 810 | data->cpu = u.val32[0]; |
811 | array++; | 811 | array++; |
812 | } | 812 | } |
813 | 813 | ||
814 | if (type & PERF_SAMPLE_PERIOD) { | 814 | if (type & PERF_SAMPLE_PERIOD) { |
815 | data->period = *array; | 815 | data->period = *array; |
816 | array++; | 816 | array++; |
817 | } | 817 | } |
818 | 818 | ||
819 | if (type & PERF_SAMPLE_READ) { | 819 | if (type & PERF_SAMPLE_READ) { |
820 | fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); | 820 | fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); |
821 | return -1; | 821 | return -1; |
822 | } | 822 | } |
823 | 823 | ||
824 | if (type & PERF_SAMPLE_CALLCHAIN) { | 824 | if (type & PERF_SAMPLE_CALLCHAIN) { |
825 | if (sample_overlap(event, array, sizeof(data->callchain->nr))) | 825 | if (sample_overlap(event, array, sizeof(data->callchain->nr))) |
826 | return -EFAULT; | 826 | return -EFAULT; |
827 | 827 | ||
828 | data->callchain = (struct ip_callchain *)array; | 828 | data->callchain = (struct ip_callchain *)array; |
829 | 829 | ||
830 | if (sample_overlap(event, array, data->callchain->nr)) | 830 | if (sample_overlap(event, array, data->callchain->nr)) |
831 | return -EFAULT; | 831 | return -EFAULT; |
832 | 832 | ||
833 | array += 1 + data->callchain->nr; | 833 | array += 1 + data->callchain->nr; |
834 | } | 834 | } |
835 | 835 | ||
836 | if (type & PERF_SAMPLE_RAW) { | 836 | if (type & PERF_SAMPLE_RAW) { |
837 | const u64 *pdata; | 837 | const u64 *pdata; |
838 | 838 | ||
839 | u.val64 = *array; | 839 | u.val64 = *array; |
840 | if (WARN_ONCE(swapped, | 840 | if (WARN_ONCE(swapped, |
841 | "Endianness of raw data not corrected!\n")) { | 841 | "Endianness of raw data not corrected!\n")) { |
842 | /* undo swap of u64, then swap on individual u32s */ | 842 | /* undo swap of u64, then swap on individual u32s */ |
843 | u.val64 = bswap_64(u.val64); | 843 | u.val64 = bswap_64(u.val64); |
844 | u.val32[0] = bswap_32(u.val32[0]); | 844 | u.val32[0] = bswap_32(u.val32[0]); |
845 | u.val32[1] = bswap_32(u.val32[1]); | 845 | u.val32[1] = bswap_32(u.val32[1]); |
846 | } | 846 | } |
847 | 847 | ||
848 | if (sample_overlap(event, array, sizeof(u32))) | 848 | if (sample_overlap(event, array, sizeof(u32))) |
849 | return -EFAULT; | 849 | return -EFAULT; |
850 | 850 | ||
851 | data->raw_size = u.val32[0]; | 851 | data->raw_size = u.val32[0]; |
852 | pdata = (void *) array + sizeof(u32); | 852 | pdata = (void *) array + sizeof(u32); |
853 | 853 | ||
854 | if (sample_overlap(event, pdata, data->raw_size)) | 854 | if (sample_overlap(event, pdata, data->raw_size)) |
855 | return -EFAULT; | 855 | return -EFAULT; |
856 | 856 | ||
857 | data->raw_data = (void *) pdata; | 857 | data->raw_data = (void *) pdata; |
858 | 858 | ||
859 | array = (void *)array + data->raw_size + sizeof(u32); | 859 | array = (void *)array + data->raw_size + sizeof(u32); |
860 | } | 860 | } |
861 | 861 | ||
862 | if (type & PERF_SAMPLE_BRANCH_STACK) { | 862 | if (type & PERF_SAMPLE_BRANCH_STACK) { |
863 | u64 sz; | 863 | u64 sz; |
864 | 864 | ||
865 | data->branch_stack = (struct branch_stack *)array; | 865 | data->branch_stack = (struct branch_stack *)array; |
866 | array++; /* nr */ | 866 | array++; /* nr */ |
867 | 867 | ||
868 | sz = data->branch_stack->nr * sizeof(struct branch_entry); | 868 | sz = data->branch_stack->nr * sizeof(struct branch_entry); |
869 | sz /= sizeof(u64); | 869 | sz /= sizeof(u64); |
870 | array += sz; | 870 | array += sz; |
871 | } | 871 | } |
872 | return 0; | 872 | return 0; |
873 | } | 873 | } |
874 | 874 | ||
875 | int perf_event__synthesize_sample(union perf_event *event, u64 type, | 875 | int perf_event__synthesize_sample(union perf_event *event, u64 type, |
876 | const struct perf_sample *sample, | 876 | const struct perf_sample *sample, |
877 | bool swapped) | 877 | bool swapped) |
878 | { | 878 | { |
879 | u64 *array; | 879 | u64 *array; |
880 | 880 | ||
881 | /* | 881 | /* |
882 | * used for cross-endian analysis. See git commit 65014ab3 | 882 | * used for cross-endian analysis. See git commit 65014ab3 |
883 | * for why this goofiness is needed. | 883 | * for why this goofiness is needed. |
884 | */ | 884 | */ |
885 | union u64_swap u; | 885 | union u64_swap u; |
886 | 886 | ||
887 | array = event->sample.array; | 887 | array = event->sample.array; |
888 | 888 | ||
889 | if (type & PERF_SAMPLE_IP) { | 889 | if (type & PERF_SAMPLE_IP) { |
890 | event->ip.ip = sample->ip; | 890 | event->ip.ip = sample->ip; |
891 | array++; | 891 | array++; |
892 | } | 892 | } |
893 | 893 | ||
894 | if (type & PERF_SAMPLE_TID) { | 894 | if (type & PERF_SAMPLE_TID) { |
895 | u.val32[0] = sample->pid; | 895 | u.val32[0] = sample->pid; |
896 | u.val32[1] = sample->tid; | 896 | u.val32[1] = sample->tid; |
897 | if (swapped) { | 897 | if (swapped) { |
898 | /* | 898 | /* |
899 | * Inverse of what is done in perf_event__parse_sample | 899 | * Inverse of what is done in perf_evsel__parse_sample |
900 | */ | 900 | */ |
901 | u.val32[0] = bswap_32(u.val32[0]); | 901 | u.val32[0] = bswap_32(u.val32[0]); |
902 | u.val32[1] = bswap_32(u.val32[1]); | 902 | u.val32[1] = bswap_32(u.val32[1]); |
903 | u.val64 = bswap_64(u.val64); | 903 | u.val64 = bswap_64(u.val64); |
904 | } | 904 | } |
905 | 905 | ||
906 | *array = u.val64; | 906 | *array = u.val64; |
907 | array++; | 907 | array++; |
908 | } | 908 | } |
909 | 909 | ||
910 | if (type & PERF_SAMPLE_TIME) { | 910 | if (type & PERF_SAMPLE_TIME) { |
911 | *array = sample->time; | 911 | *array = sample->time; |
912 | array++; | 912 | array++; |
913 | } | 913 | } |
914 | 914 | ||
915 | if (type & PERF_SAMPLE_ADDR) { | 915 | if (type & PERF_SAMPLE_ADDR) { |
916 | *array = sample->addr; | 916 | *array = sample->addr; |
917 | array++; | 917 | array++; |
918 | } | 918 | } |
919 | 919 | ||
920 | if (type & PERF_SAMPLE_ID) { | 920 | if (type & PERF_SAMPLE_ID) { |
921 | *array = sample->id; | 921 | *array = sample->id; |
922 | array++; | 922 | array++; |
923 | } | 923 | } |
924 | 924 | ||
925 | if (type & PERF_SAMPLE_STREAM_ID) { | 925 | if (type & PERF_SAMPLE_STREAM_ID) { |
926 | *array = sample->stream_id; | 926 | *array = sample->stream_id; |
927 | array++; | 927 | array++; |
928 | } | 928 | } |
929 | 929 | ||
930 | if (type & PERF_SAMPLE_CPU) { | 930 | if (type & PERF_SAMPLE_CPU) { |
931 | u.val32[0] = sample->cpu; | 931 | u.val32[0] = sample->cpu; |
932 | if (swapped) { | 932 | if (swapped) { |
933 | /* | 933 | /* |
934 | * Inverse of what is done in perf_event__parse_sample | 934 | * Inverse of what is done in perf_evsel__parse_sample |
935 | */ | 935 | */ |
936 | u.val32[0] = bswap_32(u.val32[0]); | 936 | u.val32[0] = bswap_32(u.val32[0]); |
937 | u.val64 = bswap_64(u.val64); | 937 | u.val64 = bswap_64(u.val64); |
938 | } | 938 | } |
939 | *array = u.val64; | 939 | *array = u.val64; |
940 | array++; | 940 | array++; |
941 | } | 941 | } |
942 | 942 | ||
943 | if (type & PERF_SAMPLE_PERIOD) { | 943 | if (type & PERF_SAMPLE_PERIOD) { |
944 | *array = sample->period; | 944 | *array = sample->period; |
945 | array++; | 945 | array++; |
946 | } | 946 | } |
947 | 947 | ||
948 | return 0; | 948 | return 0; |
949 | } | 949 | } |
tools/perf/util/evsel.h
1 | #ifndef __PERF_EVSEL_H | 1 | #ifndef __PERF_EVSEL_H |
2 | #define __PERF_EVSEL_H 1 | 2 | #define __PERF_EVSEL_H 1 |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include "../../../include/linux/perf_event.h" | 6 | #include "../../../include/linux/perf_event.h" |
7 | #include "types.h" | 7 | #include "types.h" |
8 | #include "xyarray.h" | 8 | #include "xyarray.h" |
9 | #include "cgroup.h" | 9 | #include "cgroup.h" |
10 | #include "hist.h" | 10 | #include "hist.h" |
11 | 11 | ||
12 | struct perf_counts_values { | 12 | struct perf_counts_values { |
13 | union { | 13 | union { |
14 | struct { | 14 | struct { |
15 | u64 val; | 15 | u64 val; |
16 | u64 ena; | 16 | u64 ena; |
17 | u64 run; | 17 | u64 run; |
18 | }; | 18 | }; |
19 | u64 values[3]; | 19 | u64 values[3]; |
20 | }; | 20 | }; |
21 | }; | 21 | }; |
22 | 22 | ||
23 | struct perf_counts { | 23 | struct perf_counts { |
24 | s8 scaled; | 24 | s8 scaled; |
25 | struct perf_counts_values aggr; | 25 | struct perf_counts_values aggr; |
26 | struct perf_counts_values cpu[]; | 26 | struct perf_counts_values cpu[]; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | struct perf_evsel; | 29 | struct perf_evsel; |
30 | 30 | ||
31 | /* | 31 | /* |
32 | * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are | 32 | * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are |
33 | * more than one entry in the evlist. | 33 | * more than one entry in the evlist. |
34 | */ | 34 | */ |
35 | struct perf_sample_id { | 35 | struct perf_sample_id { |
36 | struct hlist_node node; | 36 | struct hlist_node node; |
37 | u64 id; | 37 | u64 id; |
38 | struct perf_evsel *evsel; | 38 | struct perf_evsel *evsel; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | /** struct perf_evsel - event selector | 41 | /** struct perf_evsel - event selector |
42 | * | 42 | * |
43 | * @name - Can be set to retain the original event name passed by the user, | 43 | * @name - Can be set to retain the original event name passed by the user, |
44 | * so that when showing results in tools such as 'perf stat', we | 44 | * so that when showing results in tools such as 'perf stat', we |
45 | * show the name used, not some alias. | 45 | * show the name used, not some alias. |
46 | */ | 46 | */ |
47 | struct perf_evsel { | 47 | struct perf_evsel { |
48 | struct list_head node; | 48 | struct list_head node; |
49 | struct perf_event_attr attr; | 49 | struct perf_event_attr attr; |
50 | char *filter; | 50 | char *filter; |
51 | struct xyarray *fd; | 51 | struct xyarray *fd; |
52 | struct xyarray *sample_id; | 52 | struct xyarray *sample_id; |
53 | u64 *id; | 53 | u64 *id; |
54 | struct perf_counts *counts; | 54 | struct perf_counts *counts; |
55 | int idx; | 55 | int idx; |
56 | int ids; | 56 | int ids; |
57 | struct hists hists; | 57 | struct hists hists; |
58 | char *name; | 58 | char *name; |
59 | union { | 59 | union { |
60 | void *priv; | 60 | void *priv; |
61 | off_t id_offset; | 61 | off_t id_offset; |
62 | }; | 62 | }; |
63 | struct cgroup_sel *cgrp; | 63 | struct cgroup_sel *cgrp; |
64 | struct { | 64 | struct { |
65 | void *func; | 65 | void *func; |
66 | void *data; | 66 | void *data; |
67 | } handler; | 67 | } handler; |
68 | unsigned int sample_size; | 68 | unsigned int sample_size; |
69 | bool supported; | 69 | bool supported; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | struct cpu_map; | 72 | struct cpu_map; |
73 | struct thread_map; | 73 | struct thread_map; |
74 | struct perf_evlist; | 74 | struct perf_evlist; |
75 | struct perf_record_opts; | 75 | struct perf_record_opts; |
76 | 76 | ||
77 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); | 77 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); |
78 | void perf_evsel__init(struct perf_evsel *evsel, | 78 | void perf_evsel__init(struct perf_evsel *evsel, |
79 | struct perf_event_attr *attr, int idx); | 79 | struct perf_event_attr *attr, int idx); |
80 | void perf_evsel__exit(struct perf_evsel *evsel); | 80 | void perf_evsel__exit(struct perf_evsel *evsel); |
81 | void perf_evsel__delete(struct perf_evsel *evsel); | 81 | void perf_evsel__delete(struct perf_evsel *evsel); |
82 | 82 | ||
83 | void perf_evsel__config(struct perf_evsel *evsel, | 83 | void perf_evsel__config(struct perf_evsel *evsel, |
84 | struct perf_record_opts *opts, | 84 | struct perf_record_opts *opts, |
85 | struct perf_evsel *first); | 85 | struct perf_evsel *first); |
86 | 86 | ||
87 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); | 87 | bool perf_evsel__is_cache_op_valid(u8 type, u8 op); |
88 | 88 | ||
89 | #define PERF_EVSEL__MAX_ALIASES 8 | 89 | #define PERF_EVSEL__MAX_ALIASES 8 |
90 | 90 | ||
91 | extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] | 91 | extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] |
92 | [PERF_EVSEL__MAX_ALIASES]; | 92 | [PERF_EVSEL__MAX_ALIASES]; |
93 | extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] | 93 | extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] |
94 | [PERF_EVSEL__MAX_ALIASES]; | 94 | [PERF_EVSEL__MAX_ALIASES]; |
95 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] | 95 | const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] |
96 | [PERF_EVSEL__MAX_ALIASES]; | 96 | [PERF_EVSEL__MAX_ALIASES]; |
97 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | 97 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, |
98 | char *bf, size_t size); | 98 | char *bf, size_t size); |
99 | const char *perf_evsel__name(struct perf_evsel *evsel); | 99 | const char *perf_evsel__name(struct perf_evsel *evsel); |
100 | 100 | ||
101 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 101 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
102 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 102 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
103 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 103 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); |
104 | void perf_evsel__free_fd(struct perf_evsel *evsel); | 104 | void perf_evsel__free_fd(struct perf_evsel *evsel); |
105 | void perf_evsel__free_id(struct perf_evsel *evsel); | 105 | void perf_evsel__free_id(struct perf_evsel *evsel); |
106 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 106 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
107 | 107 | ||
108 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 108 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
109 | struct cpu_map *cpus, bool group, | 109 | struct cpu_map *cpus, bool group, |
110 | struct xyarray *group_fds); | 110 | struct xyarray *group_fds); |
111 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 111 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
112 | struct thread_map *threads, bool group, | 112 | struct thread_map *threads, bool group, |
113 | struct xyarray *group_fds); | 113 | struct xyarray *group_fds); |
114 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 114 | int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
115 | struct thread_map *threads, bool group, | 115 | struct thread_map *threads, bool group, |
116 | struct xyarray *group_fds); | 116 | struct xyarray *group_fds); |
117 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads); | 117 | void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads); |
118 | 118 | ||
119 | #define perf_evsel__match(evsel, t, c) \ | 119 | #define perf_evsel__match(evsel, t, c) \ |
120 | (evsel->attr.type == PERF_TYPE_##t && \ | 120 | (evsel->attr.type == PERF_TYPE_##t && \ |
121 | evsel->attr.config == PERF_COUNT_##c) | 121 | evsel->attr.config == PERF_COUNT_##c) |
122 | 122 | ||
123 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 123 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
124 | int cpu, int thread, bool scale); | 124 | int cpu, int thread, bool scale); |
125 | 125 | ||
126 | /** | 126 | /** |
127 | * perf_evsel__read_on_cpu - Read out the results on a CPU and thread | 127 | * perf_evsel__read_on_cpu - Read out the results on a CPU and thread |
128 | * | 128 | * |
129 | * @evsel - event selector to read value | 129 | * @evsel - event selector to read value |
130 | * @cpu - CPU of interest | 130 | * @cpu - CPU of interest |
131 | * @thread - thread of interest | 131 | * @thread - thread of interest |
132 | */ | 132 | */ |
133 | static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 133 | static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
134 | int cpu, int thread) | 134 | int cpu, int thread) |
135 | { | 135 | { |
136 | return __perf_evsel__read_on_cpu(evsel, cpu, thread, false); | 136 | return __perf_evsel__read_on_cpu(evsel, cpu, thread, false); |
137 | } | 137 | } |
138 | 138 | ||
139 | /** | 139 | /** |
140 | * perf_evsel__read_on_cpu_scaled - Read out the results on a CPU and thread, scaled | 140 | * perf_evsel__read_on_cpu_scaled - Read out the results on a CPU and thread, scaled |
141 | * | 141 | * |
142 | * @evsel - event selector to read value | 142 | * @evsel - event selector to read value |
143 | * @cpu - CPU of interest | 143 | * @cpu - CPU of interest |
144 | * @thread - thread of interest | 144 | * @thread - thread of interest |
145 | */ | 145 | */ |
146 | static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel, | 146 | static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel, |
147 | int cpu, int thread) | 147 | int cpu, int thread) |
148 | { | 148 | { |
149 | return __perf_evsel__read_on_cpu(evsel, cpu, thread, true); | 149 | return __perf_evsel__read_on_cpu(evsel, cpu, thread, true); |
150 | } | 150 | } |
151 | 151 | ||
152 | int __perf_evsel__read(struct perf_evsel *evsel, int ncpus, int nthreads, | 152 | int __perf_evsel__read(struct perf_evsel *evsel, int ncpus, int nthreads, |
153 | bool scale); | 153 | bool scale); |
154 | 154 | ||
155 | /** | 155 | /** |
156 | * perf_evsel__read - Read the aggregate results on all CPUs | 156 | * perf_evsel__read - Read the aggregate results on all CPUs |
157 | * | 157 | * |
158 | * @evsel - event selector to read value | 158 | * @evsel - event selector to read value |
159 | * @ncpus - Number of cpus affected, from zero | 159 | * @ncpus - Number of cpus affected, from zero |
160 | * @nthreads - Number of threads affected, from zero | 160 | * @nthreads - Number of threads affected, from zero |
161 | */ | 161 | */ |
162 | static inline int perf_evsel__read(struct perf_evsel *evsel, | 162 | static inline int perf_evsel__read(struct perf_evsel *evsel, |
163 | int ncpus, int nthreads) | 163 | int ncpus, int nthreads) |
164 | { | 164 | { |
165 | return __perf_evsel__read(evsel, ncpus, nthreads, false); | 165 | return __perf_evsel__read(evsel, ncpus, nthreads, false); |
166 | } | 166 | } |
167 | 167 | ||
168 | /** | 168 | /** |
169 | * perf_evsel__read_scaled - Read the aggregate results on all CPUs, scaled | 169 | * perf_evsel__read_scaled - Read the aggregate results on all CPUs, scaled |
170 | * | 170 | * |
171 | * @evsel - event selector to read value | 171 | * @evsel - event selector to read value |
172 | * @ncpus - Number of cpus affected, from zero | 172 | * @ncpus - Number of cpus affected, from zero |
173 | * @nthreads - Number of threads affected, from zero | 173 | * @nthreads - Number of threads affected, from zero |
174 | */ | 174 | */ |
175 | static inline int perf_evsel__read_scaled(struct perf_evsel *evsel, | 175 | static inline int perf_evsel__read_scaled(struct perf_evsel *evsel, |
176 | int ncpus, int nthreads) | 176 | int ncpus, int nthreads) |
177 | { | 177 | { |
178 | return __perf_evsel__read(evsel, ncpus, nthreads, true); | 178 | return __perf_evsel__read(evsel, ncpus, nthreads, true); |
179 | } | 179 | } |
180 | 180 | ||
181 | void hists__init(struct hists *hists); | 181 | void hists__init(struct hists *hists); |
182 | 182 | ||
183 | int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | ||
184 | struct perf_sample *sample, bool swapped); | ||
183 | #endif /* __PERF_EVSEL_H */ | 185 | #endif /* __PERF_EVSEL_H */ |
184 | 186 |