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]);