1 // SPDX-License-Identifier: GPL-2.0
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
13 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/bitops.h>
16 #include <linux/log2.h>
17 #include <linux/zalloc.h>
26 #include "arm-spe-pkt-decoder.h"
29 struct auxtrace auxtrace
;
30 struct auxtrace_queues queues
;
31 struct auxtrace_heap heap
;
33 struct perf_session
*session
;
34 struct machine
*machine
;
38 struct arm_spe_queue
{
40 unsigned int queue_nr
;
41 struct auxtrace_buffer
*buffer
;
49 static void arm_spe_dump(struct arm_spe
*spe __maybe_unused
,
50 unsigned char *buf
, size_t len
)
52 struct arm_spe_pkt packet
;
55 char desc
[ARM_SPE_PKT_DESC_MAX
];
56 const char *color
= PERF_COLOR_BLUE
;
58 color_fprintf(stdout
, color
,
59 ". ... ARM SPE data: size %zu bytes\n",
63 ret
= arm_spe_get_packet(buf
, len
, &packet
);
69 color_fprintf(stdout
, color
, " %08x: ", pos
);
70 for (i
= 0; i
< pkt_len
; i
++)
71 color_fprintf(stdout
, color
, " %02x", buf
[i
]);
73 color_fprintf(stdout
, color
, " ");
75 ret
= arm_spe_pkt_desc(&packet
, desc
,
76 ARM_SPE_PKT_DESC_MAX
);
78 color_fprintf(stdout
, color
, " %s\n", desc
);
80 color_fprintf(stdout
, color
, " Bad packet!\n");
88 static void arm_spe_dump_event(struct arm_spe
*spe
, unsigned char *buf
,
92 arm_spe_dump(spe
, buf
, len
);
95 static int arm_spe_process_event(struct perf_session
*session __maybe_unused
,
96 union perf_event
*event __maybe_unused
,
97 struct perf_sample
*sample __maybe_unused
,
98 struct perf_tool
*tool __maybe_unused
)
103 static int arm_spe_process_auxtrace_event(struct perf_session
*session
,
104 union perf_event
*event
,
105 struct perf_tool
*tool __maybe_unused
)
107 struct arm_spe
*spe
= container_of(session
->auxtrace
, struct arm_spe
,
109 struct auxtrace_buffer
*buffer
;
111 int fd
= perf_data__fd(session
->data
);
114 if (perf_data__is_pipe(session
->data
)) {
117 data_offset
= lseek(fd
, 0, SEEK_CUR
);
118 if (data_offset
== -1)
122 err
= auxtrace_queues__add_event(&spe
->queues
, session
, event
,
123 data_offset
, &buffer
);
127 /* Dump here now we have copied a piped trace out of the pipe */
129 if (auxtrace_buffer__get_data(buffer
, fd
)) {
130 arm_spe_dump_event(spe
, buffer
->data
,
132 auxtrace_buffer__put_data(buffer
);
139 static int arm_spe_flush(struct perf_session
*session __maybe_unused
,
140 struct perf_tool
*tool __maybe_unused
)
145 static void arm_spe_free_queue(void *priv
)
147 struct arm_spe_queue
*speq
= priv
;
154 static void arm_spe_free_events(struct perf_session
*session
)
156 struct arm_spe
*spe
= container_of(session
->auxtrace
, struct arm_spe
,
158 struct auxtrace_queues
*queues
= &spe
->queues
;
161 for (i
= 0; i
< queues
->nr_queues
; i
++) {
162 arm_spe_free_queue(queues
->queue_array
[i
].priv
);
163 queues
->queue_array
[i
].priv
= NULL
;
165 auxtrace_queues__free(queues
);
168 static void arm_spe_free(struct perf_session
*session
)
170 struct arm_spe
*spe
= container_of(session
->auxtrace
, struct arm_spe
,
173 auxtrace_heap__free(&spe
->heap
);
174 arm_spe_free_events(session
);
175 session
->auxtrace
= NULL
;
179 static const char * const arm_spe_info_fmts
[] = {
180 [ARM_SPE_PMU_TYPE
] = " PMU Type %"PRId64
"\n",
183 static void arm_spe_print_info(__u64
*arr
)
188 fprintf(stdout
, arm_spe_info_fmts
[ARM_SPE_PMU_TYPE
], arr
[ARM_SPE_PMU_TYPE
]);
191 int arm_spe_process_auxtrace_info(union perf_event
*event
,
192 struct perf_session
*session
)
194 struct perf_record_auxtrace_info
*auxtrace_info
= &event
->auxtrace_info
;
195 size_t min_sz
= sizeof(u64
) * ARM_SPE_PMU_TYPE
;
199 if (auxtrace_info
->header
.size
< sizeof(struct perf_record_auxtrace_info
) +
203 spe
= zalloc(sizeof(struct arm_spe
));
207 err
= auxtrace_queues__init(&spe
->queues
);
211 spe
->session
= session
;
212 spe
->machine
= &session
->machines
.host
; /* No kvm support */
213 spe
->auxtrace_type
= auxtrace_info
->type
;
214 spe
->pmu_type
= auxtrace_info
->priv
[ARM_SPE_PMU_TYPE
];
216 spe
->auxtrace
.process_event
= arm_spe_process_event
;
217 spe
->auxtrace
.process_auxtrace_event
= arm_spe_process_auxtrace_event
;
218 spe
->auxtrace
.flush_events
= arm_spe_flush
;
219 spe
->auxtrace
.free_events
= arm_spe_free_events
;
220 spe
->auxtrace
.free
= arm_spe_free
;
221 session
->auxtrace
= &spe
->auxtrace
;
223 arm_spe_print_info(&auxtrace_info
->priv
[0]);