Linux Audio

Check our new training course

Loading...
v4.17
  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
 29struct 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;
 37};
 38
 39struct 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;
 48};
 49
 50static 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;
 56	char desc[ARM_SPE_PKT_DESC_MAX];
 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,
 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");
 82		}
 83		pos += pkt_len;
 84		buf += pkt_len;
 85		len -= pkt_len;
 86	}
 87}
 88
 89static 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
 96static 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
104static int arm_spe_process_auxtrace_event(struct perf_session *session,
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);
133			auxtrace_buffer__put_data(buffer);
134		}
135	}
136
137	return 0;
138}
139
140static int arm_spe_flush(struct perf_session *session __maybe_unused,
141			 struct perf_tool *tool __maybe_unused)
142{
143	return 0;
144}
145
146static 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
155static void arm_spe_free_events(struct perf_session *session)
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
169static 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
180static const char * const arm_spe_info_fmts[] = {
181	[ARM_SPE_PMU_TYPE]		= "  PMU Type           %"PRId64"\n",
182};
183
184static 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
192int arm_spe_process_auxtrace_info(union perf_event *event,
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
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;
223
224	arm_spe_print_info(&auxtrace_info->priv[0]);
225
226	return 0;
227
228err_free:
229	free(spe);
230	return err;
231}
v5.4
  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 <unistd.h>
 12#include <stdlib.h>
 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>
 18
 
 19#include "color.h"
 20#include "evsel.h"
 
 21#include "machine.h"
 22#include "session.h"
 
 
 23#include "debug.h"
 24#include "auxtrace.h"
 25#include "arm-spe.h"
 26#include "arm-spe-pkt-decoder.h"
 27
 28struct arm_spe {
 29	struct auxtrace			auxtrace;
 30	struct auxtrace_queues		queues;
 31	struct auxtrace_heap		heap;
 32	u32				auxtrace_type;
 33	struct perf_session		*session;
 34	struct machine			*machine;
 35	u32				pmu_type;
 36};
 37
 38struct arm_spe_queue {
 39	struct arm_spe		*spe;
 40	unsigned int		queue_nr;
 41	struct auxtrace_buffer	*buffer;
 42	bool			on_heap;
 43	bool			done;
 44	pid_t			pid;
 45	pid_t			tid;
 46	int			cpu;
 47};
 48
 49static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
 50			 unsigned char *buf, size_t len)
 51{
 52	struct arm_spe_pkt packet;
 53	size_t pos = 0;
 54	int ret, pkt_len, i;
 55	char desc[ARM_SPE_PKT_DESC_MAX];
 56	const char *color = PERF_COLOR_BLUE;
 57
 58	color_fprintf(stdout, color,
 59		      ". ... ARM SPE data: size %zu bytes\n",
 60		      len);
 61
 62	while (len) {
 63		ret = arm_spe_get_packet(buf, len, &packet);
 64		if (ret > 0)
 65			pkt_len = ret;
 66		else
 67			pkt_len = 1;
 68		printf(".");
 69		color_fprintf(stdout, color, "  %08x: ", pos);
 70		for (i = 0; i < pkt_len; i++)
 71			color_fprintf(stdout, color, " %02x", buf[i]);
 72		for (; i < 16; i++)
 73			color_fprintf(stdout, color, "   ");
 74		if (ret > 0) {
 75			ret = arm_spe_pkt_desc(&packet, desc,
 76					       ARM_SPE_PKT_DESC_MAX);
 77			if (ret > 0)
 78				color_fprintf(stdout, color, " %s\n", desc);
 79		} else {
 80			color_fprintf(stdout, color, " Bad packet!\n");
 81		}
 82		pos += pkt_len;
 83		buf += pkt_len;
 84		len -= pkt_len;
 85	}
 86}
 87
 88static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
 89			       size_t len)
 90{
 91	printf(".\n");
 92	arm_spe_dump(spe, buf, len);
 93}
 94
 95static 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)
 99{
100	return 0;
101}
102
103static int arm_spe_process_auxtrace_event(struct perf_session *session,
104					  union perf_event *event,
105					  struct perf_tool *tool __maybe_unused)
106{
107	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
108					     auxtrace);
109	struct auxtrace_buffer *buffer;
110	off_t data_offset;
111	int fd = perf_data__fd(session->data);
112	int err;
113
114	if (perf_data__is_pipe(session->data)) {
115		data_offset = 0;
116	} else {
117		data_offset = lseek(fd, 0, SEEK_CUR);
118		if (data_offset == -1)
119			return -errno;
120	}
121
122	err = auxtrace_queues__add_event(&spe->queues, session, event,
123					 data_offset, &buffer);
124	if (err)
125		return err;
126
127	/* Dump here now we have copied a piped trace out of the pipe */
128	if (dump_trace) {
129		if (auxtrace_buffer__get_data(buffer, fd)) {
130			arm_spe_dump_event(spe, buffer->data,
131					     buffer->size);
132			auxtrace_buffer__put_data(buffer);
133		}
134	}
135
136	return 0;
137}
138
139static int arm_spe_flush(struct perf_session *session __maybe_unused,
140			 struct perf_tool *tool __maybe_unused)
141{
142	return 0;
143}
144
145static void arm_spe_free_queue(void *priv)
146{
147	struct arm_spe_queue *speq = priv;
148
149	if (!speq)
150		return;
151	free(speq);
152}
153
154static void arm_spe_free_events(struct perf_session *session)
155{
156	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
157					     auxtrace);
158	struct auxtrace_queues *queues = &spe->queues;
159	unsigned int i;
160
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;
164	}
165	auxtrace_queues__free(queues);
166}
167
168static void arm_spe_free(struct perf_session *session)
169{
170	struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
171					     auxtrace);
172
173	auxtrace_heap__free(&spe->heap);
174	arm_spe_free_events(session);
175	session->auxtrace = NULL;
176	free(spe);
177}
178
179static const char * const arm_spe_info_fmts[] = {
180	[ARM_SPE_PMU_TYPE]		= "  PMU Type           %"PRId64"\n",
181};
182
183static void arm_spe_print_info(__u64 *arr)
184{
185	if (!dump_trace)
186		return;
187
188	fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
189}
190
191int arm_spe_process_auxtrace_info(union perf_event *event,
192				  struct perf_session *session)
193{
194	struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
195	size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE;
196	struct arm_spe *spe;
197	int err;
198
199	if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) +
200					min_sz)
201		return -EINVAL;
202
203	spe = zalloc(sizeof(struct arm_spe));
204	if (!spe)
205		return -ENOMEM;
206
207	err = auxtrace_queues__init(&spe->queues);
208	if (err)
209		goto err_free;
210
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];
215
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;
222
223	arm_spe_print_info(&auxtrace_info->priv[0]);
224
225	return 0;
226
227err_free:
228	free(spe);
229	return err;
230}