Linux 5.1.15
[linux/fpc-iii.git] / tools / perf / util / arm-spe.c
blob6067267cc76c61a6241ae09caa69980ff4dd3818
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
7 #include <endian.h>
8 #include <errno.h>
9 #include <byteswap.h>
10 #include <inttypes.h>
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/bitops.h>
14 #include <linux/log2.h>
16 #include "cpumap.h"
17 #include "color.h"
18 #include "evsel.h"
19 #include "evlist.h"
20 #include "machine.h"
21 #include "session.h"
22 #include "util.h"
23 #include "thread.h"
24 #include "debug.h"
25 #include "auxtrace.h"
26 #include "arm-spe.h"
27 #include "arm-spe-pkt-decoder.h"
29 struct arm_spe {
30 struct auxtrace auxtrace;
31 struct auxtrace_queues queues;
32 struct auxtrace_heap heap;
33 u32 auxtrace_type;
34 struct perf_session *session;
35 struct machine *machine;
36 u32 pmu_type;
39 struct arm_spe_queue {
40 struct arm_spe *spe;
41 unsigned int queue_nr;
42 struct auxtrace_buffer *buffer;
43 bool on_heap;
44 bool done;
45 pid_t pid;
46 pid_t tid;
47 int cpu;
50 static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
51 unsigned char *buf, size_t len)
53 struct arm_spe_pkt packet;
54 size_t pos = 0;
55 int ret, pkt_len, i;
56 char desc[ARM_SPE_PKT_DESC_MAX];
57 const char *color = PERF_COLOR_BLUE;
59 color_fprintf(stdout, color,
60 ". ... ARM SPE data: size %zu bytes\n",
61 len);
63 while (len) {
64 ret = arm_spe_get_packet(buf, len, &packet);
65 if (ret > 0)
66 pkt_len = ret;
67 else
68 pkt_len = 1;
69 printf(".");
70 color_fprintf(stdout, color, " %08x: ", pos);
71 for (i = 0; i < pkt_len; i++)
72 color_fprintf(stdout, color, " %02x", buf[i]);
73 for (; i < 16; i++)
74 color_fprintf(stdout, color, " ");
75 if (ret > 0) {
76 ret = arm_spe_pkt_desc(&packet, desc,
77 ARM_SPE_PKT_DESC_MAX);
78 if (ret > 0)
79 color_fprintf(stdout, color, " %s\n", desc);
80 } else {
81 color_fprintf(stdout, color, " Bad packet!\n");
83 pos += pkt_len;
84 buf += pkt_len;
85 len -= pkt_len;
89 static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
90 size_t len)
92 printf(".\n");
93 arm_spe_dump(spe, buf, len);
96 static int arm_spe_process_event(struct perf_session *session __maybe_unused,
97 union perf_event *event __maybe_unused,
98 struct perf_sample *sample __maybe_unused,
99 struct perf_tool *tool __maybe_unused)
101 return 0;
104 static int arm_spe_process_auxtrace_event(struct perf_session *session,
105 union perf_event *event,
106 struct perf_tool *tool __maybe_unused)
108 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
109 auxtrace);
110 struct auxtrace_buffer *buffer;
111 off_t data_offset;
112 int fd = perf_data__fd(session->data);
113 int err;
115 if (perf_data__is_pipe(session->data)) {
116 data_offset = 0;
117 } else {
118 data_offset = lseek(fd, 0, SEEK_CUR);
119 if (data_offset == -1)
120 return -errno;
123 err = auxtrace_queues__add_event(&spe->queues, session, event,
124 data_offset, &buffer);
125 if (err)
126 return err;
128 /* Dump here now we have copied a piped trace out of the pipe */
129 if (dump_trace) {
130 if (auxtrace_buffer__get_data(buffer, fd)) {
131 arm_spe_dump_event(spe, buffer->data,
132 buffer->size);
133 auxtrace_buffer__put_data(buffer);
137 return 0;
140 static int arm_spe_flush(struct perf_session *session __maybe_unused,
141 struct perf_tool *tool __maybe_unused)
143 return 0;
146 static void arm_spe_free_queue(void *priv)
148 struct arm_spe_queue *speq = priv;
150 if (!speq)
151 return;
152 free(speq);
155 static void arm_spe_free_events(struct perf_session *session)
157 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
158 auxtrace);
159 struct auxtrace_queues *queues = &spe->queues;
160 unsigned int i;
162 for (i = 0; i < queues->nr_queues; i++) {
163 arm_spe_free_queue(queues->queue_array[i].priv);
164 queues->queue_array[i].priv = NULL;
166 auxtrace_queues__free(queues);
169 static void arm_spe_free(struct perf_session *session)
171 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
172 auxtrace);
174 auxtrace_heap__free(&spe->heap);
175 arm_spe_free_events(session);
176 session->auxtrace = NULL;
177 free(spe);
180 static const char * const arm_spe_info_fmts[] = {
181 [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n",
184 static void arm_spe_print_info(u64 *arr)
186 if (!dump_trace)
187 return;
189 fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
192 int arm_spe_process_auxtrace_info(union perf_event *event,
193 struct perf_session *session)
195 struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
196 size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE;
197 struct arm_spe *spe;
198 int err;
200 if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) +
201 min_sz)
202 return -EINVAL;
204 spe = zalloc(sizeof(struct arm_spe));
205 if (!spe)
206 return -ENOMEM;
208 err = auxtrace_queues__init(&spe->queues);
209 if (err)
210 goto err_free;
212 spe->session = session;
213 spe->machine = &session->machines.host; /* No kvm support */
214 spe->auxtrace_type = auxtrace_info->type;
215 spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
217 spe->auxtrace.process_event = arm_spe_process_event;
218 spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event;
219 spe->auxtrace.flush_events = arm_spe_flush;
220 spe->auxtrace.free_events = arm_spe_free_events;
221 spe->auxtrace.free = arm_spe_free;
222 session->auxtrace = &spe->auxtrace;
224 arm_spe_print_info(&auxtrace_info->priv[0]);
226 return 0;
228 err_free:
229 free(spe);
230 return err;