Linux Perf
arm-spe.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Arm Statistical Profiling Extensions (SPE) support
4  * Copyright (c) 2017-2018, Arm Ltd.
5  */
6 
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>
15 
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"
28 
29 struct arm_spe {
35  struct machine *machine;
36  u32 pmu_type;
37 };
38 
39 struct arm_spe_queue {
40  struct arm_spe *spe;
41  unsigned int queue_nr;
43  bool on_heap;
44  bool done;
45  pid_t pid;
46  pid_t tid;
47  int cpu;
48 };
49 
50 static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
51  unsigned char *buf, size_t len)
52 {
53  struct arm_spe_pkt packet;
54  size_t pos = 0;
55  int ret, pkt_len, i;
57  const char *color = PERF_COLOR_BLUE;
58 
59  color_fprintf(stdout, color,
60  ". ... ARM SPE data: size %zu bytes\n",
61  len);
62 
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,
78  if (ret > 0)
79  color_fprintf(stdout, color, " %s\n", desc);
80  } else {
81  color_fprintf(stdout, color, " Bad packet!\n");
82  }
83  pos += pkt_len;
84  buf += pkt_len;
85  len -= pkt_len;
86  }
87 }
88 
89 static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
90  size_t len)
91 {
92  printf(".\n");
93  arm_spe_dump(spe, buf, len);
94 }
95 
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)
100 {
101  return 0;
102 }
103 
105  union perf_event *event,
106  struct perf_tool *tool __maybe_unused)
107 {
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;
114 
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;
121  }
122 
123  err = auxtrace_queues__add_event(&spe->queues, session, event,
124  data_offset, &buffer);
125  if (err)
126  return err;
127 
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);
134  }
135  }
136 
137  return 0;
138 }
139 
140 static int arm_spe_flush(struct perf_session *session __maybe_unused,
141  struct perf_tool *tool __maybe_unused)
142 {
143  return 0;
144 }
145 
146 static void arm_spe_free_queue(void *priv)
147 {
148  struct arm_spe_queue *speq = priv;
149 
150  if (!speq)
151  return;
152  free(speq);
153 }
154 
156 {
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;
161 
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;
165  }
166  auxtrace_queues__free(queues);
167 }
168 
169 static void arm_spe_free(struct perf_session *session)
170 {
171  struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
172  auxtrace);
173 
174  auxtrace_heap__free(&spe->heap);
175  arm_spe_free_events(session);
176  session->auxtrace = NULL;
177  free(spe);
178 }
179 
180 static const char * const arm_spe_info_fmts[] = {
181  [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n",
182 };
183 
184 static void arm_spe_print_info(u64 *arr)
185 {
186  if (!dump_trace)
187  return;
188 
189  fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
190 }
191 
193  struct perf_session *session)
194 {
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;
199 
200  if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) +
201  min_sz)
202  return -EINVAL;
203 
204  spe = zalloc(sizeof(struct arm_spe));
205  if (!spe)
206  return -ENOMEM;
207 
208  err = auxtrace_queues__init(&spe->queues);
209  if (err)
210  goto err_free;
211 
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];
216 
221  spe->auxtrace.free = arm_spe_free;
222  session->auxtrace = &spe->auxtrace;
223 
224  arm_spe_print_info(&auxtrace_info->priv[0]);
225 
226  return 0;
227 
228 err_free:
229  free(spe);
230  return err;
231 }
int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, size_t buf_len)
int color_fprintf(FILE *fp, const char *color, const char *fmt,...)
Definition: color.c:123
pid_t pid
Definition: arm-spe.c:45
struct perf_data * data
Definition: session.h:36
int(* process_event)(struct perf_session *session, union perf_event *event, struct perf_sample *sample, struct perf_tool *tool)
Definition: auxtrace.h:139
static const char *const arm_spe_info_fmts[]
Definition: arm-spe.c:180
struct perf_event_header header
Definition: event.h:504
struct auxtrace_queues queues
Definition: arm-spe.c:31
struct auxtrace_queue * queue_array
Definition: auxtrace.h:219
void * auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd)
Definition: auxtrace.c:804
struct machine host
Definition: machine.h:136
struct auxtrace * auxtrace
Definition: session.h:26
int int err
Definition: 5sec.c:44
struct perf_session * session
Definition: arm-spe.c:34
void * priv
Definition: auxtrace.h:207
static void arm_spe_free_events(struct perf_session *session)
Definition: arm-spe.c:155
int auxtrace_queues__add_event(struct auxtrace_queues *queues, struct perf_session *session, union perf_event *event, off_t data_offset, struct auxtrace_buffer **buffer_ptr)
Definition: auxtrace.c:357
unsigned int nr_queues
Definition: auxtrace.h:220
#define PERF_COLOR_BLUE
Definition: color.h:16
Definition: tool.h:44
void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer)
Definition: auxtrace.c:826
static void arm_spe_dump(struct arm_spe *spe __maybe_unused, unsigned char *buf, size_t len)
Definition: arm-spe.c:50
int arm_spe_get_packet(const unsigned char *buf, size_t len, struct arm_spe_pkt *packet)
u32 pmu_type
Definition: arm-spe.c:36
static struct perf_tool tool
Definition: builtin-diff.c:362
void auxtrace_heap__free(struct auxtrace_heap *heap)
Definition: auxtrace.c:463
struct auxtrace_heap heap
Definition: arm-spe.c:32
static int arm_spe_flush(struct perf_session *session __maybe_unused, struct perf_tool *tool __maybe_unused)
Definition: arm-spe.c:140
#define event
struct arm_spe * spe
Definition: arm-spe.c:40
struct machine * machine
Definition: arm-spe.c:35
static int perf_data__fd(struct perf_data *data)
Definition: data.h:40
off_t data_offset
Definition: auxtrace.h:182
bool on_heap
Definition: arm-spe.c:43
static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf, size_t len)
Definition: arm-spe.c:89
struct auxtrace auxtrace
Definition: arm-spe.c:30
#define ARM_SPE_PKT_DESC_MAX
static void arm_spe_free(struct perf_session *session)
Definition: arm-spe.c:169
static int arm_spe_process_auxtrace_event(struct perf_session *session, union perf_event *event, struct perf_tool *tool __maybe_unused)
Definition: arm-spe.c:104
int arm_spe_process_auxtrace_info(union perf_event *event, struct perf_session *session)
Definition: arm-spe.c:192
const char * desc
Definition: clang.c:10
static int perf_data__is_pipe(struct perf_data *data)
Definition: data.h:35
void(* free_events)(struct perf_session *session)
Definition: auxtrace.h:148
int(* flush_events)(struct perf_session *session, struct perf_tool *tool)
Definition: auxtrace.h:146
static void arm_spe_print_info(u64 *arr)
Definition: arm-spe.c:184
unsigned int queue_nr
Definition: arm-spe.c:41
bool dump_trace
Definition: debug.c:27
void auxtrace_queues__free(struct auxtrace_queues *queues)
Definition: auxtrace.c:404
struct auxtrace_buffer * buffer
Definition: arm-spe.c:42
void free(void *)
void(* free)(struct perf_session *session)
Definition: auxtrace.h:149
int auxtrace_queues__init(struct auxtrace_queues *queues)
Definition: auxtrace.c:173
u32 auxtrace_type
Definition: arm-spe.c:33
static int arm_spe_process_event(struct perf_session *session __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, struct perf_tool *tool __maybe_unused)
Definition: arm-spe.c:96
struct machines machines
Definition: session.h:24
static void arm_spe_free_queue(void *priv)
Definition: arm-spe.c:146
bool done
Definition: arm-spe.c:44
pid_t tid
Definition: arm-spe.c:46
int(* process_auxtrace_event)(struct perf_session *session, union perf_event *event, struct perf_tool *tool)
Definition: auxtrace.h:143
void static void * zalloc(size_t size)
Definition: util.h:20