]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/util/cs-etm.c
perf tools: Add decoder mechanic to support dumping trace data
[linux.git] / tools / perf / util / cs-etm.c
1 /*
2  * SPDX-License-Identifier: GPL-2.0
3  *
4  * Copyright(C) 2015-2018 Linaro Limited.
5  *
6  * Author: Tor Jeremiassen <tor@ti.com>
7  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
8  */
9
10 #include <linux/bitops.h>
11 #include <linux/err.h>
12 #include <linux/kernel.h>
13 #include <linux/log2.h>
14 #include <linux/types.h>
15
16 #include <stdlib.h>
17
18 #include "auxtrace.h"
19 #include "color.h"
20 #include "cs-etm.h"
21 #include "cs-etm-decoder/cs-etm-decoder.h"
22 #include "debug.h"
23 #include "evlist.h"
24 #include "intlist.h"
25 #include "machine.h"
26 #include "map.h"
27 #include "perf.h"
28 #include "thread.h"
29 #include "thread_map.h"
30 #include "thread-stack.h"
31 #include "util.h"
32
33 #define MAX_TIMESTAMP (~0ULL)
34
35 struct cs_etm_auxtrace {
36         struct auxtrace auxtrace;
37         struct auxtrace_queues queues;
38         struct auxtrace_heap heap;
39         struct itrace_synth_opts synth_opts;
40         struct perf_session *session;
41         struct machine *machine;
42         struct thread *unknown_thread;
43
44         u8 timeless_decoding;
45         u8 snapshot_mode;
46         u8 data_queued;
47         u8 sample_branches;
48
49         int num_cpu;
50         u32 auxtrace_type;
51         u64 branches_sample_type;
52         u64 branches_id;
53         u64 **metadata;
54         u64 kernel_start;
55         unsigned int pmu_type;
56 };
57
58 struct cs_etm_queue {
59         struct cs_etm_auxtrace *etm;
60         struct thread *thread;
61         struct cs_etm_decoder *decoder;
62         struct auxtrace_buffer *buffer;
63         const struct cs_etm_state *state;
64         union perf_event *event_buf;
65         unsigned int queue_nr;
66         pid_t pid, tid;
67         int cpu;
68         u64 time;
69         u64 timestamp;
70         u64 offset;
71 };
72
73 static void cs_etm__packet_dump(const char *pkt_string)
74 {
75         const char *color = PERF_COLOR_BLUE;
76         int len = strlen(pkt_string);
77
78         if (len && (pkt_string[len-1] == '\n'))
79                 color_fprintf(stdout, color, "  %s", pkt_string);
80         else
81                 color_fprintf(stdout, color, "  %s\n", pkt_string);
82
83         fflush(stdout);
84 }
85
86 static void cs_etm__dump_event(struct cs_etm_auxtrace *etm,
87                                struct auxtrace_buffer *buffer)
88 {
89         int i, ret;
90         const char *color = PERF_COLOR_BLUE;
91         struct cs_etm_decoder_params d_params;
92         struct cs_etm_trace_params *t_params;
93         struct cs_etm_decoder *decoder;
94         size_t buffer_used = 0;
95
96         fprintf(stdout, "\n");
97         color_fprintf(stdout, color,
98                      ". ... CoreSight ETM Trace data: size %zu bytes\n",
99                      buffer->size);
100
101         /* Use metadata to fill in trace parameters for trace decoder */
102         t_params = zalloc(sizeof(*t_params) * etm->num_cpu);
103         for (i = 0; i < etm->num_cpu; i++) {
104                 t_params[i].protocol = CS_ETM_PROTO_ETMV4i;
105                 t_params[i].etmv4.reg_idr0 = etm->metadata[i][CS_ETMV4_TRCIDR0];
106                 t_params[i].etmv4.reg_idr1 = etm->metadata[i][CS_ETMV4_TRCIDR1];
107                 t_params[i].etmv4.reg_idr2 = etm->metadata[i][CS_ETMV4_TRCIDR2];
108                 t_params[i].etmv4.reg_idr8 = etm->metadata[i][CS_ETMV4_TRCIDR8];
109                 t_params[i].etmv4.reg_configr =
110                                         etm->metadata[i][CS_ETMV4_TRCCONFIGR];
111                 t_params[i].etmv4.reg_traceidr =
112                                         etm->metadata[i][CS_ETMV4_TRCTRACEIDR];
113         }
114
115         /* Set decoder parameters to simply print the trace packets */
116         d_params.packet_printer = cs_etm__packet_dump;
117         d_params.operation = CS_ETM_OPERATION_PRINT;
118         d_params.formatted = true;
119         d_params.fsyncs = false;
120         d_params.hsyncs = false;
121         d_params.frame_aligned = true;
122
123         decoder = cs_etm_decoder__new(etm->num_cpu, &d_params, t_params);
124
125         zfree(&t_params);
126
127         if (!decoder)
128                 return;
129         do {
130                 size_t consumed;
131
132                 ret = cs_etm_decoder__process_data_block(
133                                 decoder, buffer->offset,
134                                 &((u8 *)buffer->data)[buffer_used],
135                                 buffer->size - buffer_used, &consumed);
136                 if (ret)
137                         break;
138
139                 buffer_used += consumed;
140         } while (buffer_used < buffer->size);
141
142         cs_etm_decoder__free(decoder);
143 }
144
145 static int cs_etm__flush_events(struct perf_session *session,
146                                 struct perf_tool *tool)
147 {
148         (void) session;
149         (void) tool;
150         return 0;
151 }
152
153 static void cs_etm__free_queue(void *priv)
154 {
155         struct cs_etm_queue *etmq = priv;
156
157         free(etmq);
158 }
159
160 static void cs_etm__free_events(struct perf_session *session)
161 {
162         unsigned int i;
163         struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
164                                                    struct cs_etm_auxtrace,
165                                                    auxtrace);
166         struct auxtrace_queues *queues = &aux->queues;
167
168         for (i = 0; i < queues->nr_queues; i++) {
169                 cs_etm__free_queue(queues->queue_array[i].priv);
170                 queues->queue_array[i].priv = NULL;
171         }
172
173         auxtrace_queues__free(queues);
174 }
175
176 static void cs_etm__free(struct perf_session *session)
177 {
178         int i;
179         struct int_node *inode, *tmp;
180         struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
181                                                    struct cs_etm_auxtrace,
182                                                    auxtrace);
183         cs_etm__free_events(session);
184         session->auxtrace = NULL;
185
186         /* First remove all traceID/CPU# nodes for the RB tree */
187         intlist__for_each_entry_safe(inode, tmp, traceid_list)
188                 intlist__remove(traceid_list, inode);
189         /* Then the RB tree itself */
190         intlist__delete(traceid_list);
191
192         for (i = 0; i < aux->num_cpu; i++)
193                 zfree(&aux->metadata[i]);
194
195         zfree(&aux->metadata);
196         zfree(&aux);
197 }
198
199 static int cs_etm__process_event(struct perf_session *session,
200                                  union perf_event *event,
201                                  struct perf_sample *sample,
202                                  struct perf_tool *tool)
203 {
204         (void) session;
205         (void) event;
206         (void) sample;
207         (void) tool;
208         return 0;
209 }
210
211 static int cs_etm__process_auxtrace_event(struct perf_session *session,
212                                           union perf_event *event,
213                                           struct perf_tool *tool __maybe_unused)
214 {
215         struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
216                                                    struct cs_etm_auxtrace,
217                                                    auxtrace);
218         if (!etm->data_queued) {
219                 struct auxtrace_buffer *buffer;
220                 off_t  data_offset;
221                 int fd = perf_data__fd(session->data);
222                 bool is_pipe = perf_data__is_pipe(session->data);
223                 int err;
224
225                 if (is_pipe)
226                         data_offset = 0;
227                 else {
228                         data_offset = lseek(fd, 0, SEEK_CUR);
229                         if (data_offset == -1)
230                                 return -errno;
231                 }
232
233                 err = auxtrace_queues__add_event(&etm->queues, session,
234                                                  event, data_offset, &buffer);
235                 if (err)
236                         return err;
237
238                 if (dump_trace)
239                         if (auxtrace_buffer__get_data(buffer, fd)) {
240                                 cs_etm__dump_event(etm, buffer);
241                                 auxtrace_buffer__put_data(buffer);
242                         }
243         }
244
245         return 0;
246 }
247
248 static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
249 {
250         struct perf_evsel *evsel;
251         struct perf_evlist *evlist = etm->session->evlist;
252         bool timeless_decoding = true;
253
254         /*
255          * Circle through the list of event and complain if we find one
256          * with the time bit set.
257          */
258         evlist__for_each_entry(evlist, evsel) {
259                 if ((evsel->attr.sample_type & PERF_SAMPLE_TIME))
260                         timeless_decoding = false;
261         }
262
263         return timeless_decoding;
264 }
265
266 static const char * const cs_etm_global_header_fmts[] = {
267         [CS_HEADER_VERSION_0]   = "     Header version                 %llx\n",
268         [CS_PMU_TYPE_CPUS]      = "     PMU type/num cpus              %llx\n",
269         [CS_ETM_SNAPSHOT]       = "     Snapshot                       %llx\n",
270 };
271
272 static const char * const cs_etm_priv_fmts[] = {
273         [CS_ETM_MAGIC]          = "     Magic number                   %llx\n",
274         [CS_ETM_CPU]            = "     CPU                            %lld\n",
275         [CS_ETM_ETMCR]          = "     ETMCR                          %llx\n",
276         [CS_ETM_ETMTRACEIDR]    = "     ETMTRACEIDR                    %llx\n",
277         [CS_ETM_ETMCCER]        = "     ETMCCER                        %llx\n",
278         [CS_ETM_ETMIDR]         = "     ETMIDR                         %llx\n",
279 };
280
281 static const char * const cs_etmv4_priv_fmts[] = {
282         [CS_ETM_MAGIC]          = "     Magic number                   %llx\n",
283         [CS_ETM_CPU]            = "     CPU                            %lld\n",
284         [CS_ETMV4_TRCCONFIGR]   = "     TRCCONFIGR                     %llx\n",
285         [CS_ETMV4_TRCTRACEIDR]  = "     TRCTRACEIDR                    %llx\n",
286         [CS_ETMV4_TRCIDR0]      = "     TRCIDR0                        %llx\n",
287         [CS_ETMV4_TRCIDR1]      = "     TRCIDR1                        %llx\n",
288         [CS_ETMV4_TRCIDR2]      = "     TRCIDR2                        %llx\n",
289         [CS_ETMV4_TRCIDR8]      = "     TRCIDR8                        %llx\n",
290         [CS_ETMV4_TRCAUTHSTATUS] = "    TRCAUTHSTATUS                  %llx\n",
291 };
292
293 static void cs_etm__print_auxtrace_info(u64 *val, int num)
294 {
295         int i, j, cpu = 0;
296
297         for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
298                 fprintf(stdout, cs_etm_global_header_fmts[i], val[i]);
299
300         for (i = CS_HEADER_VERSION_0_MAX; cpu < num; cpu++) {
301                 if (val[i] == __perf_cs_etmv3_magic)
302                         for (j = 0; j < CS_ETM_PRIV_MAX; j++, i++)
303                                 fprintf(stdout, cs_etm_priv_fmts[j], val[i]);
304                 else if (val[i] == __perf_cs_etmv4_magic)
305                         for (j = 0; j < CS_ETMV4_PRIV_MAX; j++, i++)
306                                 fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]);
307                 else
308                         /* failure.. return */
309                         return;
310         }
311 }
312
313 int cs_etm__process_auxtrace_info(union perf_event *event,
314                                   struct perf_session *session)
315 {
316         struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
317         struct cs_etm_auxtrace *etm = NULL;
318         struct int_node *inode;
319         unsigned int pmu_type;
320         int event_header_size = sizeof(struct perf_event_header);
321         int info_header_size;
322         int total_size = auxtrace_info->header.size;
323         int priv_size = 0;
324         int num_cpu;
325         int err = 0, idx = -1;
326         int i, j, k;
327         u64 *ptr, *hdr = NULL;
328         u64 **metadata = NULL;
329
330         /*
331          * sizeof(auxtrace_info_event::type) +
332          * sizeof(auxtrace_info_event::reserved) == 8
333          */
334         info_header_size = 8;
335
336         if (total_size < (event_header_size + info_header_size))
337                 return -EINVAL;
338
339         priv_size = total_size - event_header_size - info_header_size;
340
341         /* First the global part */
342         ptr = (u64 *) auxtrace_info->priv;
343
344         /* Look for version '0' of the header */
345         if (ptr[0] != 0)
346                 return -EINVAL;
347
348         hdr = zalloc(sizeof(*hdr) * CS_HEADER_VERSION_0_MAX);
349         if (!hdr)
350                 return -ENOMEM;
351
352         /* Extract header information - see cs-etm.h for format */
353         for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
354                 hdr[i] = ptr[i];
355         num_cpu = hdr[CS_PMU_TYPE_CPUS] & 0xffffffff;
356         pmu_type = (unsigned int) ((hdr[CS_PMU_TYPE_CPUS] >> 32) &
357                                     0xffffffff);
358
359         /*
360          * Create an RB tree for traceID-CPU# tuple. Since the conversion has
361          * to be made for each packet that gets decoded, optimizing access in
362          * anything other than a sequential array is worth doing.
363          */
364         traceid_list = intlist__new(NULL);
365         if (!traceid_list) {
366                 err = -ENOMEM;
367                 goto err_free_hdr;
368         }
369
370         metadata = zalloc(sizeof(*metadata) * num_cpu);
371         if (!metadata) {
372                 err = -ENOMEM;
373                 goto err_free_traceid_list;
374         }
375
376         /*
377          * The metadata is stored in the auxtrace_info section and encodes
378          * the configuration of the ARM embedded trace macrocell which is
379          * required by the trace decoder to properly decode the trace due
380          * to its highly compressed nature.
381          */
382         for (j = 0; j < num_cpu; j++) {
383                 if (ptr[i] == __perf_cs_etmv3_magic) {
384                         metadata[j] = zalloc(sizeof(*metadata[j]) *
385                                              CS_ETM_PRIV_MAX);
386                         if (!metadata[j]) {
387                                 err = -ENOMEM;
388                                 goto err_free_metadata;
389                         }
390                         for (k = 0; k < CS_ETM_PRIV_MAX; k++)
391                                 metadata[j][k] = ptr[i + k];
392
393                         /* The traceID is our handle */
394                         idx = metadata[j][CS_ETM_ETMTRACEIDR];
395                         i += CS_ETM_PRIV_MAX;
396                 } else if (ptr[i] == __perf_cs_etmv4_magic) {
397                         metadata[j] = zalloc(sizeof(*metadata[j]) *
398                                              CS_ETMV4_PRIV_MAX);
399                         if (!metadata[j]) {
400                                 err = -ENOMEM;
401                                 goto err_free_metadata;
402                         }
403                         for (k = 0; k < CS_ETMV4_PRIV_MAX; k++)
404                                 metadata[j][k] = ptr[i + k];
405
406                         /* The traceID is our handle */
407                         idx = metadata[j][CS_ETMV4_TRCTRACEIDR];
408                         i += CS_ETMV4_PRIV_MAX;
409                 }
410
411                 /* Get an RB node for this CPU */
412                 inode = intlist__findnew(traceid_list, idx);
413
414                 /* Something went wrong, no need to continue */
415                 if (!inode) {
416                         err = PTR_ERR(inode);
417                         goto err_free_metadata;
418                 }
419
420                 /*
421                  * The node for that CPU should not be taken.
422                  * Back out if that's the case.
423                  */
424                 if (inode->priv) {
425                         err = -EINVAL;
426                         goto err_free_metadata;
427                 }
428                 /* All good, associate the traceID with the CPU# */
429                 inode->priv = &metadata[j][CS_ETM_CPU];
430         }
431
432         /*
433          * Each of CS_HEADER_VERSION_0_MAX, CS_ETM_PRIV_MAX and
434          * CS_ETMV4_PRIV_MAX mark how many double words are in the
435          * global metadata, and each cpu's metadata respectively.
436          * The following tests if the correct number of double words was
437          * present in the auxtrace info section.
438          */
439         if (i * 8 != priv_size) {
440                 err = -EINVAL;
441                 goto err_free_metadata;
442         }
443
444         etm = zalloc(sizeof(*etm));
445
446         if (!etm) {
447                 err = -ENOMEM;
448                 goto err_free_metadata;
449         }
450
451         err = auxtrace_queues__init(&etm->queues);
452         if (err)
453                 goto err_free_etm;
454
455         etm->session = session;
456         etm->machine = &session->machines.host;
457
458         etm->num_cpu = num_cpu;
459         etm->pmu_type = pmu_type;
460         etm->snapshot_mode = (hdr[CS_ETM_SNAPSHOT] != 0);
461         etm->metadata = metadata;
462         etm->auxtrace_type = auxtrace_info->type;
463         etm->timeless_decoding = cs_etm__is_timeless_decoding(etm);
464
465         etm->auxtrace.process_event = cs_etm__process_event;
466         etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;
467         etm->auxtrace.flush_events = cs_etm__flush_events;
468         etm->auxtrace.free_events = cs_etm__free_events;
469         etm->auxtrace.free = cs_etm__free;
470         session->auxtrace = &etm->auxtrace;
471
472         if (dump_trace) {
473                 cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
474                 return 0;
475         }
476
477         err = auxtrace_queues__process_index(&etm->queues, session);
478         if (err)
479                 goto err_free_queues;
480
481         etm->data_queued = etm->queues.populated;
482
483         return 0;
484
485 err_free_queues:
486         auxtrace_queues__free(&etm->queues);
487         session->auxtrace = NULL;
488 err_free_etm:
489         zfree(&etm);
490 err_free_metadata:
491         /* No need to check @metadata[j], free(NULL) is supported */
492         for (j = 0; j < num_cpu; j++)
493                 free(metadata[j]);
494         zfree(&metadata);
495 err_free_traceid_list:
496         intlist__delete(traceid_list);
497 err_free_hdr:
498         zfree(&hdr);
499
500         return -EINVAL;
501 }