diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 174 |
1 files changed, 26 insertions, 148 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 0c5e4f72f2ba..e566bbe3f22d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -12,28 +12,24 @@ | |||
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; |
23 | 21 | ||
24 | static struct rb_root threads; | ||
25 | static struct thread *last_match; | ||
26 | |||
27 | static struct perf_header *header; | 22 | static struct perf_header *header; |
28 | static u64 sample_type; | 23 | static u64 sample_type; |
29 | 24 | ||
25 | static char *cwd; | ||
26 | static int cwdlen; | ||
27 | |||
30 | 28 | ||
31 | static int | 29 | static int |
32 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) | 30 | process_comm_event(event_t *event, unsigned long offset, unsigned long head) |
33 | { | 31 | { |
34 | struct thread *thread; | 32 | struct thread *thread = threads__findnew(event->comm.pid); |
35 | |||
36 | thread = threads__findnew(event->comm.pid, &threads, &last_match); | ||
37 | 33 | ||
38 | dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", | 34 | dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n", |
39 | (void *)(offset + head), | 35 | (void *)(offset + head), |
@@ -53,18 +49,12 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head) | |||
53 | static int | 49 | static int |
54 | process_sample_event(event_t *event, unsigned long offset, unsigned long head) | 50 | process_sample_event(event_t *event, unsigned long offset, unsigned long head) |
55 | { | 51 | { |
56 | char level; | ||
57 | int show = 0; | ||
58 | struct dso *dso = NULL; | ||
59 | struct thread *thread; | ||
60 | u64 ip = event->ip.ip; | 52 | u64 ip = event->ip.ip; |
61 | u64 timestamp = -1; | 53 | u64 timestamp = -1; |
62 | u32 cpu = -1; | 54 | u32 cpu = -1; |
63 | u64 period = 1; | 55 | u64 period = 1; |
64 | void *more_data = event->ip.__more_data; | 56 | void *more_data = event->ip.__more_data; |
65 | int cpumode; | 57 | struct thread *thread = threads__findnew(event->ip.pid); |
66 | |||
67 | thread = threads__findnew(event->ip.pid, &threads, &last_match); | ||
68 | 58 | ||
69 | if (sample_type & PERF_SAMPLE_TIME) { | 59 | if (sample_type & PERF_SAMPLE_TIME) { |
70 | timestamp = *(u64 *)more_data; | 60 | timestamp = *(u64 *)more_data; |
@@ -90,37 +80,13 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
90 | (void *)(long)ip, | 80 | (void *)(long)ip, |
91 | (long long)period); | 81 | (long long)period); |
92 | 82 | ||
93 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | ||
94 | |||
95 | if (thread == NULL) { | 83 | if (thread == NULL) { |
96 | eprintf("problem processing %d event, skipping it.\n", | 84 | pr_debug("problem processing %d event, skipping it.\n", |
97 | event->header.type); | 85 | event->header.type); |
98 | return -1; | 86 | return -1; |
99 | } | 87 | } |
100 | 88 | ||
101 | cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 89 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); |
102 | |||
103 | if (cpumode == PERF_RECORD_MISC_KERNEL) { | ||
104 | show = SHOW_KERNEL; | ||
105 | level = 'k'; | ||
106 | |||
107 | dso = kernel_dso; | ||
108 | |||
109 | dump_printf(" ...... dso: %s\n", dso->name); | ||
110 | |||
111 | } else if (cpumode == PERF_RECORD_MISC_USER) { | ||
112 | |||
113 | show = SHOW_USER; | ||
114 | level = '.'; | ||
115 | |||
116 | } else { | ||
117 | show = SHOW_HV; | ||
118 | level = 'H'; | ||
119 | |||
120 | dso = hypervisor_dso; | ||
121 | |||
122 | dump_printf(" ...... dso: [hypervisor]\n"); | ||
123 | } | ||
124 | 90 | ||
125 | if (sample_type & PERF_SAMPLE_RAW) { | 91 | if (sample_type & PERF_SAMPLE_RAW) { |
126 | struct { | 92 | struct { |
@@ -140,121 +106,32 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head) | |||
140 | return 0; | 106 | return 0; |
141 | } | 107 | } |
142 | 108 | ||
143 | static int | 109 | static int sample_type_check(u64 type) |
144 | process_event(event_t *event, unsigned long offset, unsigned long head) | ||
145 | { | 110 | { |
146 | trace_event(event); | 111 | sample_type = type; |
147 | |||
148 | switch (event->header.type) { | ||
149 | case PERF_RECORD_MMAP ... PERF_RECORD_LOST: | ||
150 | return 0; | ||
151 | |||
152 | case PERF_RECORD_COMM: | ||
153 | return process_comm_event(event, offset, head); | ||
154 | 112 | ||
155 | case PERF_RECORD_EXIT ... PERF_RECORD_READ: | 113 | if (!(sample_type & PERF_SAMPLE_RAW)) { |
156 | return 0; | 114 | fprintf(stderr, |
157 | 115 | "No trace sample to read. Did you call perf record " | |
158 | case PERF_RECORD_SAMPLE: | 116 | "without -R?"); |
159 | return process_sample_event(event, offset, head); | ||
160 | |||
161 | case PERF_RECORD_MAX: | ||
162 | default: | ||
163 | return -1; | 117 | return -1; |
164 | } | 118 | } |
165 | 119 | ||
166 | return 0; | 120 | return 0; |
167 | } | 121 | } |
168 | 122 | ||
123 | static struct perf_file_handler file_handler = { | ||
124 | .process_sample_event = process_sample_event, | ||
125 | .process_comm_event = process_comm_event, | ||
126 | .sample_type_check = sample_type_check, | ||
127 | }; | ||
128 | |||
169 | static int __cmd_trace(void) | 129 | static int __cmd_trace(void) |
170 | { | 130 | { |
171 | int ret, rc = EXIT_FAILURE; | 131 | register_idle_thread(); |
172 | unsigned long offset = 0; | 132 | register_perf_file_handler(&file_handler); |
173 | unsigned long head = 0; | ||
174 | struct stat perf_stat; | ||
175 | event_t *event; | ||
176 | uint32_t size; | ||
177 | char *buf; | ||
178 | |||
179 | trace_report(); | ||
180 | register_idle_thread(&threads, &last_match); | ||
181 | |||
182 | input = open(input_name, O_RDONLY); | ||
183 | if (input < 0) { | ||
184 | perror("failed to open file"); | ||
185 | exit(-1); | ||
186 | } | ||
187 | |||
188 | ret = fstat(input, &perf_stat); | ||
189 | if (ret < 0) { | ||
190 | perror("failed to stat file"); | ||
191 | exit(-1); | ||
192 | } | ||
193 | |||
194 | if (!perf_stat.st_size) { | ||
195 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | ||
196 | exit(0); | ||
197 | } | ||
198 | header = perf_header__read(input); | ||
199 | head = header->data_offset; | ||
200 | sample_type = perf_header__sample_type(header); | ||
201 | |||
202 | if (!(sample_type & PERF_SAMPLE_RAW)) | ||
203 | die("No trace sample to read. Did you call perf record " | ||
204 | "without -R?"); | ||
205 | |||
206 | if (load_kernel() < 0) { | ||
207 | perror("failed to load kernel symbols"); | ||
208 | return EXIT_FAILURE; | ||
209 | } | ||
210 | |||
211 | remap: | ||
212 | buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ, | ||
213 | MAP_SHARED, input, offset); | ||
214 | if (buf == MAP_FAILED) { | ||
215 | perror("failed to mmap file"); | ||
216 | exit(-1); | ||
217 | } | ||
218 | |||
219 | more: | ||
220 | event = (event_t *)(buf + head); | ||
221 | |||
222 | if (head + event->header.size >= page_size * mmap_window) { | ||
223 | unsigned long shift = page_size * (head / page_size); | ||
224 | int res; | ||
225 | |||
226 | res = munmap(buf, page_size * mmap_window); | ||
227 | assert(res == 0); | ||
228 | |||
229 | offset += shift; | ||
230 | head -= shift; | ||
231 | goto remap; | ||
232 | } | ||
233 | |||
234 | size = event->header.size; | ||
235 | |||
236 | if (!size || process_event(event, offset, head) < 0) { | ||
237 | |||
238 | /* | ||
239 | * assume we lost track of the stream, check alignment, and | ||
240 | * increment a single u64 in the hope to catch on again 'soon'. | ||
241 | */ | ||
242 | |||
243 | if (unlikely(head & 7)) | ||
244 | head &= ~7ULL; | ||
245 | |||
246 | size = 8; | ||
247 | } | ||
248 | |||
249 | head += size; | ||
250 | |||
251 | if (offset + head < (unsigned long)perf_stat.st_size) | ||
252 | goto more; | ||
253 | |||
254 | rc = EXIT_SUCCESS; | ||
255 | close(input); | ||
256 | 133 | ||
257 | return rc; | 134 | return mmap_dispatch_perf_file(&header, input_name, 0, 0, &cwdlen, &cwd); |
258 | } | 135 | } |
259 | 136 | ||
260 | static const char * const annotate_usage[] = { | 137 | static const char * const annotate_usage[] = { |
@@ -267,13 +144,14 @@ static const struct option options[] = { | |||
267 | "dump raw trace in ASCII"), | 144 | "dump raw trace in ASCII"), |
268 | OPT_BOOLEAN('v', "verbose", &verbose, | 145 | OPT_BOOLEAN('v', "verbose", &verbose, |
269 | "be more verbose (show symbol address, etc)"), | 146 | "be more verbose (show symbol address, etc)"), |
147 | OPT_BOOLEAN('l', "latency", &latency_format, | ||
148 | "show latency attributes (irqs/preemption disabled, etc)"), | ||
270 | OPT_END() | 149 | OPT_END() |
271 | }; | 150 | }; |
272 | 151 | ||
273 | int cmd_trace(int argc, const char **argv, const char *prefix __used) | 152 | int cmd_trace(int argc, const char **argv, const char *prefix __used) |
274 | { | 153 | { |
275 | symbol__init(); | 154 | symbol__init(); |
276 | page_size = getpagesize(); | ||
277 | 155 | ||
278 | argc = parse_options(argc, argv, options, annotate_usage, 0); | 156 | argc = parse_options(argc, argv, options, annotate_usage, 0); |
279 | if (argc) { | 157 | if (argc) { |