Skip to content

Commit cd8bfd8

Browse files
tor-jeremiassenmathieupoirier
authored andcommitted
perf tools: Add processing of coresight metadata
The auxtrace_info section contains metadata that describes the number of trace capable CPUs, their ETM version and trace configuration, including trace id values. This information is required by the trace decoder in order to properly decode the compressed trace packets. This patch adds code to read and parse this metadata, and store it for use in configuring instances of the cs-etm trace decoder. Co-authored-by: Mathieu Poirier <[email protected]> Signed-off-by: Tor Jeremiassen <[email protected]> Acked-by: Jiri Olsa <[email protected]> Cc: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Kim Phillips <[email protected]> Cc: Mike Leach <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Suzuki Poulouse <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 440a23b commit cd8bfd8

File tree

2 files changed

+194
-3
lines changed

2 files changed

+194
-3
lines changed

tools/perf/util/cs-etm.c

Lines changed: 191 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,24 @@ static void cs_etm__free_events(struct perf_session *session)
102102

103103
static void cs_etm__free(struct perf_session *session)
104104
{
105+
int i;
106+
struct int_node *inode, *tmp;
105107
struct cs_etm_auxtrace *aux = container_of(session->auxtrace,
106108
struct cs_etm_auxtrace,
107109
auxtrace);
108110
cs_etm__free_events(session);
109111
session->auxtrace = NULL;
110112

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);
111123
zfree(&aux);
112124
}
113125

@@ -151,15 +163,69 @@ static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
151163
return timeless_decoding;
152164
}
153165

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+
154213
int cs_etm__process_auxtrace_info(union perf_event *event,
155214
struct perf_session *session)
156215
{
157216
struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
158217
struct cs_etm_auxtrace *etm = NULL;
218+
struct int_node *inode;
219+
unsigned int pmu_type;
159220
int event_header_size = sizeof(struct perf_event_header);
160221
int info_header_size;
161222
int total_size = auxtrace_info->header.size;
162-
int err = 0;
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;
163229

164230
/*
165231
* sizeof(auxtrace_info_event::type) +
@@ -170,10 +236,117 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
170236
if (total_size < (event_header_size + info_header_size))
171237
return -EINVAL;
172238

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+
173344
etm = zalloc(sizeof(*etm));
174345

175-
if (!etm)
346+
if (!etm) {
176347
err = -ENOMEM;
348+
goto err_free_metadata;
349+
}
177350

178351
err = auxtrace_queues__init(&etm->queues);
179352
if (err)
@@ -182,6 +355,10 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
182355
etm->session = session;
183356
etm->machine = &session->machines.host;
184357

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;
185362
etm->auxtrace_type = auxtrace_info->type;
186363
etm->timeless_decoding = cs_etm__is_timeless_decoding(etm);
187364

@@ -192,8 +369,10 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
192369
etm->auxtrace.free = cs_etm__free;
193370
session->auxtrace = &etm->auxtrace;
194371

195-
if (dump_trace)
372+
if (dump_trace) {
373+
cs_etm__print_auxtrace_info(auxtrace_info->priv, num_cpu);
196374
return 0;
375+
}
197376

198377
err = auxtrace_queues__process_index(&etm->queues, session);
199378
if (err)
@@ -208,6 +387,15 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
208387
session->auxtrace = NULL;
209388
err_free_etm:
210389
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);
211399

212400
return -EINVAL;
213401
}

tools/perf/util/cs-etm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ enum {
6464
CS_ETMV4_PRIV_MAX,
6565
};
6666

67+
/* RB tree for quick conversion between traceID and CPUs */
68+
struct intlist *traceid_list;
69+
6770
#define KiB(x) ((x) * 1024)
6871
#define MiB(x) ((x) * 1024 * 1024)
6972

0 commit comments

Comments
 (0)