diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-10-07 06:47:31 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-10-08 10:56:32 -0400 |
commit | 016e92fbc9ef33689cf654f343a94383d43235e7 (patch) | |
tree | edf9dc21d037ea138300b7e7e32574e6f6f17fb2 /tools/perf/builtin-trace.c | |
parent | 03456a158d9067d2f657bec170506009db81756d (diff) |
perf tools: Unify perf.data mapping and events handling
This librarizes the perf.data file mapping and handling in various
perf tools, roughly reducing the amount of code and fixing the
places that mmap from beginning of the file whereas we want to mmap
from the beginning of the data, leading to page fault because the
mmap window is too small since the trace info are written in the
file too.
TODO:
- convert perf timechart too
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arjan van de Ven <arjan@infradead.org>
LKML-Reference: <20091007104729.GD5043@nowhere>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 129 |
1 files changed, 18 insertions, 111 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d9abb4ae5f79..fb3f3c220211 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -12,11 +12,9 @@ | |||
12 | #include "util/debug.h" | 12 | #include "util/debug.h" |
13 | 13 | ||
14 | #include "util/trace-event.h" | 14 | #include "util/trace-event.h" |
15 | #include "util/data_map.h" | ||
15 | 16 | ||
16 | static char const *input_name = "perf.data"; | 17 | static char const *input_name = "perf.data"; |
17 | static int input; | ||
18 | static unsigned long page_size; | ||
19 | static unsigned long mmap_window = 32; | ||
20 | 18 | ||
21 | static unsigned long total = 0; | 19 | static unsigned long total = 0; |
22 | static unsigned long total_comm = 0; | 20 | static unsigned long total_comm = 0; |
@@ -27,6 +25,9 @@ static struct thread *last_match; | |||
27 | static struct perf_header *header; | 25 | static struct perf_header *header; |
28 | static u64 sample_type; | 26 | static u64 sample_type; |
29 | 27 | ||
28 | static char *cwd; | ||
29 | static int cwdlen; | ||
30 | |||
30 | 31 | ||
31 | static int | 32 | static int |
32 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 33 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) |
@@ -112,125 +113,32 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
112 | return 0; | 113 | return 0; |
113 | } | 114 | } |
114 | 115 | ||
115 | static int | 116 | static int sample_type_check(u64 type) |
116 | process_event(event_t *event, unsigned long offset, unsigned long head) | ||
117 | { | 117 | { |
118 | trace_event(event); | 118 | sample_type = type; |
119 | |||
120 | switch (event->header.type) { | ||
121 | case PERF_RECORD_MMAP ... PERF_RECORD_LOST: | ||
122 | return 0; | ||
123 | |||
124 | case PERF_RECORD_COMM: | ||
125 | return process_comm_event(event, offset, head); | ||
126 | |||
127 | case PERF_RECORD_EXIT ... PERF_RECORD_READ: | ||
128 | return 0; | ||
129 | 119 | ||
130 | case PERF_RECORD_SAMPLE: | 120 | if (!(sample_type & PERF_SAMPLE_RAW)) { |
131 | return process_sample_event(event, offset, head); | 121 | fprintf(stderr, |
132 | 122 | "No trace sample to read. Did you call perf record " | |
133 | case PERF_RECORD_MAX: | 123 | "without -R?"); |
134 | default: | ||
135 | return -1; | 124 | return -1; |
136 | } | 125 | } |
137 | 126 | ||
138 | return 0; | 127 | return 0; |
139 | } | 128 | } |
140 | 129 | ||
130 | static struct perf_file_handler file_handler = { | ||
131 | .process_sample_event = process_sample_event, | ||
132 | .process_comm_event = process_comm_event, | ||
133 | .sample_type_check = sample_type_check, | ||
134 | }; | ||
135 | |||
141 | static int __cmd_trace(void) | 136 | static int __cmd_trace(void) |
142 | { | 137 | { |
143 | int ret, rc = EXIT_FAILURE; | ||
144 | unsigned long offset = 0; | ||
145 | unsigned long head = 0; | ||
146 | unsigned long shift; | ||
147 | struct stat perf_stat; | ||
148 | event_t *event; | ||
149 | uint32_t size; | ||
150 | char *buf; | ||
151 | |||
152 | register_idle_thread(&threads, &last_match); | 138 | register_idle_thread(&threads, &last_match); |
139 | register_perf_file_handler(&file_handler); | ||
153 | 140 | ||
154 | input = open(input_name, O_RDONLY); | 141 | return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); |
155 | if (input < 0) { | ||
156 | perror("failed to open file"); | ||
157 | exit(-1); | ||
158 | } | ||
159 | |||
160 | ret = fstat(input, &perf_stat); | ||
161 | if (ret < 0) { | ||
162 | perror("failed to stat file"); | ||
163 | exit(-1); | ||
164 | } | ||
165 | |||
166 | if (!perf_stat.st_size) { | ||
167 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | ||
168 | exit(0); | ||
169 | } | ||
170 | header = perf_header__read(input); | ||
171 | head = header->data_offset; | ||
172 | sample_type = perf_header__sample_type(header); | ||
173 | |||
174 | if (!(sample_type & PERF_SAMPLE_RAW)) | ||
175 | die("No trace sample to read. Did you call perf record " | ||
176 | "without -R?"); | ||
177 | |||
178 | if (load_kernel() < 0) { | ||
179 | perror("failed to load kernel symbols"); | ||
180 | return EXIT_FAILURE; | ||
181 | } | ||
182 | |||
183 | shift = page_size * (head / page_size); | ||
184 | offset += shift; | ||
185 | head -= shift; | ||
186 | |||
187 | remap: | ||
188 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, | ||
189 | MAP_SHARED, input, offset); | ||
190 | if (buf == MAP_FAILED) { | ||
191 | perror("failed to mmap file"); | ||
192 | exit(-1); | ||
193 | } | ||
194 | |||
195 | more: | ||
196 | event = (event_t *)(buf + head); | ||
197 | |||
198 | if (head + event->header.size >= page_size * mmap_window) { | ||
199 | int res; | ||
200 | |||
201 | shift = page_size * (head / page_size); | ||
202 | res = munmap(buf, page_size * mmap_window); | ||
203 | assert(res == 0); | ||
204 | |||
205 | offset += shift; | ||
206 | head -= shift; | ||
207 | goto remap; | ||
208 | } | ||
209 | |||
210 | size = event->header.size; | ||
211 | |||
212 | if (!size || process_event(event, offset, head) < 0) { | ||
213 | |||
214 | /* | ||
215 | * assume we lost track of the stream, check alignment, and | ||
216 | * increment a single u64 in the hope to catch on again 'soon'. | ||
217 | */ | ||
218 | |||
219 | if (unlikely(head & 7)) | ||
220 | head &= ~7ULL; | ||
221 | |||
222 | size = 8; | ||
223 | } | ||
224 | |||
225 | head += size; | ||
226 | |||
227 | if (offset + head < (unsigned long)perf_stat.st_size) | ||
228 | goto more; | ||
229 | |||
230 | rc = EXIT_SUCCESS; | ||
231 | close(input); | ||
232 | |||
233 | return rc; | ||
234 | } | 142 | } |
235 | 143 | ||
236 | static const char * const annotate_usage[] = { | 144 | static const char * const annotate_usage[] = { |
@@ -249,7 +157,6 @@ static const struct option options[] = { | |||
249 | int cmd_trace(int argc, const char **argv, const char *prefix __used) | 157 | int cmd_trace(int argc, const char **argv, const char *prefix __used) |
250 | { | 158 | { |
251 | symbol__init(); | 159 | symbol__init(); |
252 | page_size = getpagesize(); | ||
253 | 160 | ||
254 | argc = parse_options(argc, argv, options, annotate_usage, 0); | 161 | argc = parse_options(argc, argv, options, annotate_usage, 0); |
255 | if (argc) { | 162 | if (argc) { |