]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/util/cs-etm.c
perf tools: Add processing of coresight metadata
[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 "debug.h"
22 #include "evlist.h"
23 #include "intlist.h"
24 #include "machine.h"
25 #include "map.h"
26 #include "perf.h"
27 #include "thread.h"
28 #include "thread_map.h"
29 #include "thread-stack.h"
30 #include "util.h"
31
32 #define MAX_TIMESTAMP (~0ULL)
33
34 struct cs_etm_auxtrace {
35         struct auxtrace auxtrace;
36         struct auxtrace_queues queues;
37         struct auxtrace_heap heap;
38         struct itrace_synth_opts synth_opts;
39         struct perf_session *session;
40         struct machine *machine;
41         struct thread *unknown_thread;
42
43         u8 timeless_decoding;
44         u8 snapshot_mode;
45         u8 data_queued;
46         u8 sample_branches;
47
48         int num_cpu;
49         u32 auxtrace_type;
50         u64 branches_sample_type;
51         u64 branches_id;
52         u64 **metadata;
53         u64 kernel_start;
54         unsigned int pmu_type;
55 };
56
57 struct cs_etm_queue {
58         struct cs_etm_auxtrace *etm;
59         struct thread *thread;
60         struct cs_etm_decoder *decoder;
61         struct auxtrace_buffer *buffer;
62         const struct cs_etm_state *state;
63         union perf_event *event_buf;
64         unsigned int queue_nr;
65         pid_t pid, tid;
66         int cpu;
67         u64 time;
68         u64 timestamp;
69         u64 offset;
70 };
71
72 static int cs_etm__flush_events(struct perf_session *session,
73                                 struct perf_tool *tool)
74 {
75         (void) session;
76         (void) tool;
77         return 0;
78 }
79
80 static void cs_etm__free_queue(void *priv)
81 {
82         struct cs_etm_queue *etmq = priv;
83
84         free(etmq);
85 }
86
87 static void cs_etm__free_events(struct perf_session *session)
88 {
89         unsigned int i;
90         struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
91                                                    struct cs_etm_auxtrace,
92                                                    auxtrace);
93         struct auxtrace_queues *queues = &aux->queues;
94
95         for (i = 0; i < queues->nr_queues; i++) {
96                 cs_etm__free_queue(queues->queue_array[i].priv);
97                 queues->queue_array[i].priv = NULL;
98         }
99
100         auxtrace_queues__free(queues);
101 }
102
103 static void cs_etm__free(struct perf_session *session)
104 {
105         int i;
106         struct int_node *inode, *tmp;
107         struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
108                                                    struct cs_etm_auxtrace,
109                                                    auxtrace);
110         cs_etm__free_events(session);
111         session->auxtrace = NULL;
112
113         /* First remove all traceID/CPU# nodes for the RB tree */
114         intlist__for_each_entry_safe(inode, tmp, traceid_list)
115                 intlist__remove(traceid_list, inode);
116         /* Then the RB tree itself */
117         intlist__delete(traceid_list);
118
119         for (i = 0; i < aux->num_cpu; i++)
120                 zfree(&aux->metadata[i]);
121
122         zfree(&aux->metadata);
123         zfree(&aux);
124 }
125
126 static int cs_etm__process_event(struct perf_session *session,
127                                  union perf_event *event,
128                                  struct perf_sample *sample,
129                                  struct perf_tool *tool)
130 {
131         (void) session;
132         (void) event;
133         (void) sample;
134         (void) tool;
135         return 0;
136 }
137
138 static int cs_etm__process_auxtrace_event(struct perf_session *session,
139                                           union perf_event *event,
140                                           struct perf_tool *tool)
141 {
142         (void) session;
143         (void) event;
144         (void) tool;
145         return 0;
146 }
147
148 static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
149 {
150         struct perf_evsel *evsel;
151         struct perf_evlist *evlist = etm->session->evlist;
152         bool timeless_decoding = true;
153
154         /*
155          * Circle through the list of event and complain if we find one
156          * with the time bit set.
157          */
158         evlist__for_each_entry(evlist, evsel) {
159                 if ((evsel->attr.sample_type & PERF_SAMPLE_TIME))
160                         timeless_decoding = false;
161         }
162
163         return timeless_decoding;
164 }
165
166 static const char * const cs_etm_global_header_fmts[] = {
167         [CS_HEADER_VERSION_0]   = "     Header version                 %llx\n",
168         [CS_PMU_TYPE_CPUS]      = "     PMU type/num cpus              %llx\n",
169         [CS_ETM_SNAPSHOT]       = "     Snapshot                       %llx\n",
170 };
171
172 static const char * const cs_etm_priv_fmts[] = {
173         [CS_ETM_MAGIC]          = "     Magic number                   %llx\n",
174         [CS_ETM_CPU]            = "     CPU                            %lld\n",
175         [CS_ETM_ETMCR]          = "     ETMCR                          %llx\n",
176         [CS_ETM_ETMTRACEIDR]    = "     ETMTRACEIDR                    %llx\n",
177         [CS_ETM_ETMCCER]        = "     ETMCCER                        %llx\n",
178         [CS_ETM_ETMIDR]         = "     ETMIDR                         %llx\n",
179 };
180
181 static const char * const cs_etmv4_priv_fmts[] = {
182         [CS_ETM_MAGIC]          = "     Magic number                   %llx\n",
183         [CS_ETM_CPU]            = "     CPU                            %lld\n",
184         [CS_ETMV4_TRCCONFIGR]   = "     TRCCONFIGR                     %llx\n",
185         [CS_ETMV4_TRCTRACEIDR]  = "     TRCTRACEIDR                    %llx\n",
186         [CS_ETMV4_TRCIDR0]      = "     TRCIDR0                        %llx\n",
187         [CS_ETMV4_TRCIDR1]      = "     TRCIDR1                        %llx\n",
188         [CS_ETMV4_TRCIDR2]      = "     TRCIDR2                        %llx\n",
189         [CS_ETMV4_TRCIDR8]      = "     TRCIDR8                        %llx\n",
190         [CS_ETMV4_TRCAUTHSTATUS] = "    TRCAUTHSTATUS                  %llx\n",
191 };
192
193 static void cs_etm__print_auxtrace_info(u64 *val, int num)
194 {
195         int i, j, cpu = 0;
196
197         for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
198                 fprintf(stdout, cs_etm_global_header_fmts[i], val[i]);
199
200         for (i = CS_HEADER_VERSION_0_MAX; cpu < num; cpu++) {
201                 if (val[i] == __perf_cs_etmv3_magic)
202                         for (j = 0; j < CS_ETM_PRIV_MAX; j++, i++)
203                                 fprintf(stdout, cs_etm_priv_fmts[j], val[i]);
204                 else if (val[i] == __perf_cs_etmv4_magic)
205                         for (j = 0; j < CS_ETMV4_PRIV_MAX; j++, i++)
206                                 fprintf(stdout, cs_etmv4_priv_fmts[j], val[i]);
207                 else
208                         /* failure.. return */
209                         return;
210         }
211 }
212
213 int cs_etm__process_auxtrace_info(union perf_event *event,
214                                   struct perf_session *session)
215 {
216         struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
217         struct cs_etm_auxtrace *etm = NULL;
218         struct int_node *inode;
219         unsigned int pmu_type;
220         int event_header_size = sizeof(struct perf_event_header);
221         int info_header_size;
222         int total_size = auxtrace_info->header.size;
223         int priv_size = 0;
224         int num_cpu;
225         int err = 0, idx = -1;
226         int i, j, k;
227         u64 *ptr, *hdr = NULL;
228         u64 **metadata = NULL;
229
230         /*
231          * sizeof(auxtrace_info_event::type) +
232          * sizeof(auxtrace_info_event::reserved) == 8
233          */
234         info_header_size = 8;
235
236         if (total_size < (event_header_size + info_header_size))
237                 return -EINVAL;
238
239         priv_size = total_size - event_header_size - info_header_size;
240
241         /* First the global part */
242         ptr = (u64 *) auxtrace_info->priv;
243
244         /* Look for version '0' of the header */
245         if (ptr[0] != 0)
246                 return -EINVAL;
247
248         hdr = zalloc(sizeof(*hdr) * CS_HEADER_VERSION_0_MAX);
249         if (!hdr)
250                 return -ENOMEM;
251
252         /* Extract header information - see cs-etm.h for format */
253         for (i = 0; i < CS_HEADER_VERSION_0_MAX; i++)
254                 hdr[i] = ptr[i];
255         num_cpu = hdr[CS_PMU_TYPE_CPUS] & 0xffffffff;
256         pmu_type = (unsigned int) ((hdr[CS_PMU_TYPE_CPUS] >> 32) &
257                                     0xffffffff);
258
259         /*
260          * Create an RB tree for traceID-CPU# tuple. Since the conversion has
261          * to be made for each packet that gets decoded, optimizing access in
262          * anything other than a sequential array is worth doing.
263          */
264         traceid_list = intlist__new(NULL);
265         if (!traceid_list) {
266                 err = -ENOMEM;
267                 goto err_free_hdr;
268         }
269
270         metadata = zalloc(sizeof(*metadata) * num_cpu);
271         if (!metadata) {
272                 err = -ENOMEM;
273                 goto err_free_traceid_list;
274         }
275
276         /*
277          * The metadata is stored in the auxtrace_info section and encodes
278          * the configuration of the ARM embedded trace macrocell which is
279          * required by the trace decoder to properly decode the trace due
280          * to its highly compressed nature.
281          */
282         for (j = 0; j < num_cpu; j++) {
283                 if (ptr[i] == __perf_cs_etmv3_magic) {
284                         metadata[j] = zalloc(sizeof(*metadata[j]) *
285                                              CS_ETM_PRIV_MAX);
286                         if (!metadata[j]) {
287                                 err = -ENOMEM;
288                                 goto err_free_metadata;
289                         }
290                         for (k = 0; k < CS_ETM_PRIV_MAX; k++)
291                                 metadata[j][k] = ptr[i + k];
292
293                         /* The traceID is our handle */
294                         idx = metadata[j][CS_ETM_ETMTRACEIDR];
295                         i += CS_ETM_PRIV_MAX;
296                 } else if (ptr[i] == __perf_cs_etmv4_magic) {
297                         metadata[j] = zalloc(sizeof(*metadata[j]) *
298                                              CS_ETMV4_PRIV_MAX);
299                         if (!metadata[j]) {
300                                 err = -ENOMEM;
301                                 goto err_free_metadata;
302                         }
303                         for (k = 0; k < CS_ETMV4_PRIV_MAX; k++)
304                                 metadata[j][k] = ptr[i + k];
305
306                         /* The traceID is our handle */
307                         idx = metadata[j][CS_ETMV4_TRCTRACEIDR];
308                         i += CS_ETMV4_PRIV_MAX;
309                 }
310
311                 /* Get an RB node for this CPU */
312                 inode = intlist__findnew(traceid_list, idx);
313
314                 /* Something went wrong, no need to continue */
315                 if (!inode) {
316                         err = PTR_ERR(inode);
317                         goto err_free_metadata;
318                 }
319
320                 /*
321                  * The node for that CPU should not be taken.
322                  * Back out if that's the case.
323                  */
324                 if (inode->priv) {
325                         err = -EINVAL;
326                         goto err_free_metadata;
327                 }
328                 /* All good, associate the traceID with the CPU# */
329                 inode->priv = &metadata[j][CS_ETM_CPU];
330         }
331
332         /*
333          * Each of CS_HEADER_VERSION_0_MAX, CS_ETM_PRIV_MAX and
334          * CS_ETMV4_PRIV_MAX mark how many double words are in the
335          * global metadata, and each cpu's metadata respectively.
336          * The following tests if the correct number of double words was
337          * present in the auxtrace info section.
338          */
339         if (i * 8 != priv_size) {
340                 err = -EINVAL;
341                 goto err_free_metadata;
342         }
343
344         etm = zalloc(sizeof(*etm));
345
346         if (!etm) {
347                 err = -ENOMEM;
348                 goto err_free_metadata;
349         }
350
351         err = auxtrace_queues__init(&etm->queues);
352         if (err)
353                 goto err_free_etm;
354
355         etm->session = session;
356         etm->machine = &session->machines.host;
357
358         etm->num_cpu = num_cpu;
359         etm->pmu_type = pmu_type;
360         etm->snapshot_mode = (hdr[CS_ETM_SNAPSHOT] != 0);
361         etm->metadata = metadata;
362         etm->auxtrace_type = auxtrace_info->type;
363         etm->timeless_decoding = cs_etm__is_timeless_decoding(etm);
364
365         etm->auxtrace.process_event = cs_etm__process_event;
366         etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;
367         etm->auxtrace.flush_events = cs_etm__flush_events;
368         etm->auxtrace.free_events = cs_etm__free_events;
369         etm->auxtrace.free = cs_etm__free;
370         session->auxtrace = &etm->auxtrace;
371
372         if (dump_trace) {
373                 cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
374                 return 0;
375         }
376
377         err = auxtrace_queues__process_index(&etm->queues, session);
378         if (err)
379                 goto err_free_queues;
380
381         etm->data_queued = etm->queues.populated;
382
383         return 0;
384
385 err_free_queues:
386         auxtrace_queues__free(&etm->queues);
387         session->auxtrace = NULL;
388 err_free_etm:
389         zfree(&etm);
390 err_free_metadata:
391         /* No need to check @metadata[j], free(NULL) is supported */
392         for (j = 0; j < num_cpu; j++)
393                 free(metadata[j]);
394         zfree(&metadata);
395 err_free_traceid_list:
396         intlist__delete(traceid_list);
397 err_free_hdr:
398         zfree(&hdr);
399
400         return -EINVAL;
401 }