xref: /aosp_15_r20/external/igt-gpu-tools/overlay/gpu-perf.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
1*d83cc019SAndroid Build Coastguard Worker /*
2*d83cc019SAndroid Build Coastguard Worker  * Copyright © 2013 Intel Corporation
3*d83cc019SAndroid Build Coastguard Worker  *
4*d83cc019SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
5*d83cc019SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
6*d83cc019SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
7*d83cc019SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*d83cc019SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
9*d83cc019SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
10*d83cc019SAndroid Build Coastguard Worker  *
11*d83cc019SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice (including the next
12*d83cc019SAndroid Build Coastguard Worker  * paragraph) shall be included in all copies or substantial portions of the
13*d83cc019SAndroid Build Coastguard Worker  * Software.
14*d83cc019SAndroid Build Coastguard Worker  *
15*d83cc019SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*d83cc019SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*d83cc019SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18*d83cc019SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*d83cc019SAndroid Build Coastguard Worker  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*d83cc019SAndroid Build Coastguard Worker  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21*d83cc019SAndroid Build Coastguard Worker  * IN THE SOFTWARE.
22*d83cc019SAndroid Build Coastguard Worker  *
23*d83cc019SAndroid Build Coastguard Worker  */
24*d83cc019SAndroid Build Coastguard Worker 
25*d83cc019SAndroid Build Coastguard Worker #include <stdint.h>
26*d83cc019SAndroid Build Coastguard Worker #include <stdbool.h>
27*d83cc019SAndroid Build Coastguard Worker #include <sys/types.h>
28*d83cc019SAndroid Build Coastguard Worker #include <sys/mman.h>
29*d83cc019SAndroid Build Coastguard Worker #include <sys/ioctl.h>
30*d83cc019SAndroid Build Coastguard Worker #include <unistd.h>
31*d83cc019SAndroid Build Coastguard Worker #include <stdlib.h>
32*d83cc019SAndroid Build Coastguard Worker #include <stdio.h>
33*d83cc019SAndroid Build Coastguard Worker #include <string.h>
34*d83cc019SAndroid Build Coastguard Worker #include <fcntl.h>
35*d83cc019SAndroid Build Coastguard Worker #include <errno.h>
36*d83cc019SAndroid Build Coastguard Worker #include <assert.h>
37*d83cc019SAndroid Build Coastguard Worker 
38*d83cc019SAndroid Build Coastguard Worker #include "igt_perf.h"
39*d83cc019SAndroid Build Coastguard Worker 
40*d83cc019SAndroid Build Coastguard Worker #include "gpu-perf.h"
41*d83cc019SAndroid Build Coastguard Worker #include "debugfs.h"
42*d83cc019SAndroid Build Coastguard Worker 
43*d83cc019SAndroid Build Coastguard Worker #if defined(__i386__)
44*d83cc019SAndroid Build Coastguard Worker #define rmb()           asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
45*d83cc019SAndroid Build Coastguard Worker #define wmb()           asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
46*d83cc019SAndroid Build Coastguard Worker #endif
47*d83cc019SAndroid Build Coastguard Worker 
48*d83cc019SAndroid Build Coastguard Worker #if defined(__x86_64__)
49*d83cc019SAndroid Build Coastguard Worker #define rmb()           asm volatile("lfence" ::: "memory")
50*d83cc019SAndroid Build Coastguard Worker #define wmb()           asm volatile("sfence" ::: "memory")
51*d83cc019SAndroid Build Coastguard Worker #endif
52*d83cc019SAndroid Build Coastguard Worker 
53*d83cc019SAndroid Build Coastguard Worker #define N_PAGES 32
54*d83cc019SAndroid Build Coastguard Worker 
55*d83cc019SAndroid Build Coastguard Worker struct sample_event {
56*d83cc019SAndroid Build Coastguard Worker 	struct perf_event_header header;
57*d83cc019SAndroid Build Coastguard Worker 	uint32_t pid, tid;
58*d83cc019SAndroid Build Coastguard Worker 	uint64_t time;
59*d83cc019SAndroid Build Coastguard Worker 	uint64_t id;
60*d83cc019SAndroid Build Coastguard Worker 	uint32_t raw_size;
61*d83cc019SAndroid Build Coastguard Worker 	uint8_t tracepoint_data[0];
62*d83cc019SAndroid Build Coastguard Worker };
63*d83cc019SAndroid Build Coastguard Worker 
64*d83cc019SAndroid Build Coastguard Worker enum {
65*d83cc019SAndroid Build Coastguard Worker 	TP_GEM_REQUEST_ADD,
66*d83cc019SAndroid Build Coastguard Worker 	TP_GEM_REQUEST_WAIT_BEGIN,
67*d83cc019SAndroid Build Coastguard Worker 	TP_GEM_REQUEST_WAIT_END,
68*d83cc019SAndroid Build Coastguard Worker 	TP_FLIP_COMPLETE,
69*d83cc019SAndroid Build Coastguard Worker 	TP_GEM_RING_SYNC_TO,
70*d83cc019SAndroid Build Coastguard Worker 	TP_GEM_RING_SWITCH_CONTEXT,
71*d83cc019SAndroid Build Coastguard Worker 
72*d83cc019SAndroid Build Coastguard Worker 	TP_NB
73*d83cc019SAndroid Build Coastguard Worker };
74*d83cc019SAndroid Build Coastguard Worker 
75*d83cc019SAndroid Build Coastguard Worker struct tracepoint {
76*d83cc019SAndroid Build Coastguard Worker 	const char *name;
77*d83cc019SAndroid Build Coastguard Worker 	int event_id;
78*d83cc019SAndroid Build Coastguard Worker 
79*d83cc019SAndroid Build Coastguard Worker 	struct {
80*d83cc019SAndroid Build Coastguard Worker 		char name[128];
81*d83cc019SAndroid Build Coastguard Worker 		int offset;
82*d83cc019SAndroid Build Coastguard Worker 		int size;
83*d83cc019SAndroid Build Coastguard Worker 		int is_signed;
84*d83cc019SAndroid Build Coastguard Worker 	} fields[20];
85*d83cc019SAndroid Build Coastguard Worker 	int n_fields;
86*d83cc019SAndroid Build Coastguard Worker 
87*d83cc019SAndroid Build Coastguard Worker 	int device_field;
88*d83cc019SAndroid Build Coastguard Worker 	int ctx_field;
89*d83cc019SAndroid Build Coastguard Worker 	int class_field;
90*d83cc019SAndroid Build Coastguard Worker 	int instance_field;
91*d83cc019SAndroid Build Coastguard Worker 	int seqno_field;
92*d83cc019SAndroid Build Coastguard Worker 	int global_seqno_field;
93*d83cc019SAndroid Build Coastguard Worker 	int plane_field;
94*d83cc019SAndroid Build Coastguard Worker } tracepoints[TP_NB] = {
95*d83cc019SAndroid Build Coastguard Worker 	[TP_GEM_REQUEST_ADD]         = { .name = "i915/i915_request_add", },
96*d83cc019SAndroid Build Coastguard Worker 	[TP_GEM_REQUEST_WAIT_BEGIN]  = { .name = "i915/i915_request_wait_begin", },
97*d83cc019SAndroid Build Coastguard Worker 	[TP_GEM_REQUEST_WAIT_END]    = { .name = "i915/i915_request_wait_end", },
98*d83cc019SAndroid Build Coastguard Worker 	[TP_FLIP_COMPLETE]           = { .name = "i915/flip_complete", },
99*d83cc019SAndroid Build Coastguard Worker 	[TP_GEM_RING_SYNC_TO]        = { .name = "i915/gem_ring_sync_to", },
100*d83cc019SAndroid Build Coastguard Worker 	[TP_GEM_RING_SWITCH_CONTEXT] = { .name = "i915/gem_ring_switch_context", },
101*d83cc019SAndroid Build Coastguard Worker };
102*d83cc019SAndroid Build Coastguard Worker 
103*d83cc019SAndroid Build Coastguard Worker union parser_value {
104*d83cc019SAndroid Build Coastguard Worker     char *string;
105*d83cc019SAndroid Build Coastguard Worker     int integer;
106*d83cc019SAndroid Build Coastguard Worker };
107*d83cc019SAndroid Build Coastguard Worker 
108*d83cc019SAndroid Build Coastguard Worker struct parser_ctx {
109*d83cc019SAndroid Build Coastguard Worker 	struct tracepoint *tp;
110*d83cc019SAndroid Build Coastguard Worker 	FILE *fp;
111*d83cc019SAndroid Build Coastguard Worker };
112*d83cc019SAndroid Build Coastguard Worker 
113*d83cc019SAndroid Build Coastguard Worker #define YY_CTX_LOCAL
114*d83cc019SAndroid Build Coastguard Worker #define YY_CTX_MEMBERS struct parser_ctx ctx;
115*d83cc019SAndroid Build Coastguard Worker #define YYSTYPE union parser_value
116*d83cc019SAndroid Build Coastguard Worker #define YY_LOCAL(T) static __attribute__((unused)) T
117*d83cc019SAndroid Build Coastguard Worker #define YY_PARSE(T) static T
118*d83cc019SAndroid Build Coastguard Worker #define YY_INPUT(yy, buf, result, max)				\
119*d83cc019SAndroid Build Coastguard Worker 	{							\
120*d83cc019SAndroid Build Coastguard Worker 		int c = getc(yy->ctx.fp);			\
121*d83cc019SAndroid Build Coastguard Worker 		result = (EOF == c) ? 0 : (*(buf)= c, 1);	\
122*d83cc019SAndroid Build Coastguard Worker 		if (EOF != c) {					\
123*d83cc019SAndroid Build Coastguard Worker 			yyprintf((stderr, "<%c>", c));		\
124*d83cc019SAndroid Build Coastguard Worker 		}						\
125*d83cc019SAndroid Build Coastguard Worker 	}
126*d83cc019SAndroid Build Coastguard Worker 
127*d83cc019SAndroid Build Coastguard Worker #include "tracepoint_format.h"
128*d83cc019SAndroid Build Coastguard Worker 
129*d83cc019SAndroid Build Coastguard Worker static int
tracepoint_id(int tp_id)130*d83cc019SAndroid Build Coastguard Worker tracepoint_id(int tp_id)
131*d83cc019SAndroid Build Coastguard Worker {
132*d83cc019SAndroid Build Coastguard Worker 	struct tracepoint *tp = &tracepoints[tp_id];
133*d83cc019SAndroid Build Coastguard Worker 	yycontext ctx;
134*d83cc019SAndroid Build Coastguard Worker 	char buf[1024];
135*d83cc019SAndroid Build Coastguard Worker 
136*d83cc019SAndroid Build Coastguard Worker 	/* Already parsed? */
137*d83cc019SAndroid Build Coastguard Worker 	if (tp->event_id != 0)
138*d83cc019SAndroid Build Coastguard Worker 		return tp->event_id;
139*d83cc019SAndroid Build Coastguard Worker 
140*d83cc019SAndroid Build Coastguard Worker 	snprintf(buf, sizeof(buf), "%s/tracing/events/%s/format",
141*d83cc019SAndroid Build Coastguard Worker 		 debugfs_path, tp->name);
142*d83cc019SAndroid Build Coastguard Worker 
143*d83cc019SAndroid Build Coastguard Worker 	memset(&ctx, 0, sizeof(ctx));
144*d83cc019SAndroid Build Coastguard Worker 	ctx.ctx.tp = tp;
145*d83cc019SAndroid Build Coastguard Worker 	ctx.ctx.fp = fopen(buf, "r");
146*d83cc019SAndroid Build Coastguard Worker 
147*d83cc019SAndroid Build Coastguard Worker 	if (ctx.ctx.fp == NULL)
148*d83cc019SAndroid Build Coastguard Worker 		return 0;
149*d83cc019SAndroid Build Coastguard Worker 
150*d83cc019SAndroid Build Coastguard Worker 	if (yyparse(&ctx)) {
151*d83cc019SAndroid Build Coastguard Worker 		for (int f = 0; f < tp->n_fields; f++) {
152*d83cc019SAndroid Build Coastguard Worker 			if (!strcmp(tp->fields[f].name, "device")) {
153*d83cc019SAndroid Build Coastguard Worker 				tp->device_field = f;
154*d83cc019SAndroid Build Coastguard Worker 			} else if (!strcmp(tp->fields[f].name, "ctx")) {
155*d83cc019SAndroid Build Coastguard Worker 				tp->ctx_field = f;
156*d83cc019SAndroid Build Coastguard Worker 			} else if (!strcmp(tp->fields[f].name, "class")) {
157*d83cc019SAndroid Build Coastguard Worker 				tp->class_field = f;
158*d83cc019SAndroid Build Coastguard Worker 			} else if (!strcmp(tp->fields[f].name, "instance")) {
159*d83cc019SAndroid Build Coastguard Worker 				tp->instance_field = f;
160*d83cc019SAndroid Build Coastguard Worker 			} else if (!strcmp(tp->fields[f].name, "seqno")) {
161*d83cc019SAndroid Build Coastguard Worker 				tp->seqno_field = f;
162*d83cc019SAndroid Build Coastguard Worker 			} else if (!strcmp(tp->fields[f].name, "global_seqno")) {
163*d83cc019SAndroid Build Coastguard Worker 				tp->global_seqno_field = f;
164*d83cc019SAndroid Build Coastguard Worker 			} else if (!strcmp(tp->fields[f].name, "plane")) {
165*d83cc019SAndroid Build Coastguard Worker 				tp->plane_field = f;
166*d83cc019SAndroid Build Coastguard Worker 			}
167*d83cc019SAndroid Build Coastguard Worker 		}
168*d83cc019SAndroid Build Coastguard Worker 	} else
169*d83cc019SAndroid Build Coastguard Worker 		tp->event_id = tp->n_fields = 0;
170*d83cc019SAndroid Build Coastguard Worker 
171*d83cc019SAndroid Build Coastguard Worker 	yyrelease(&ctx);
172*d83cc019SAndroid Build Coastguard Worker 	fclose(ctx.ctx.fp);
173*d83cc019SAndroid Build Coastguard Worker 
174*d83cc019SAndroid Build Coastguard Worker 	return tp->event_id;
175*d83cc019SAndroid Build Coastguard Worker }
176*d83cc019SAndroid Build Coastguard Worker 
177*d83cc019SAndroid Build Coastguard Worker #define READ_TP_FIELD_U32(sample, tp_id, field_name)			\
178*d83cc019SAndroid Build Coastguard Worker 	(*(const uint32_t *)((sample)->tracepoint_data +		\
179*d83cc019SAndroid Build Coastguard Worker 			     tracepoints[tp_id].fields[			\
180*d83cc019SAndroid Build Coastguard Worker 				     tracepoints[tp_id].field_name##_field].offset))
181*d83cc019SAndroid Build Coastguard Worker 
182*d83cc019SAndroid Build Coastguard Worker #define READ_TP_FIELD_U16(sample, tp_id, field_name)			\
183*d83cc019SAndroid Build Coastguard Worker 	(*(const uint16_t *)((sample)->tracepoint_data +		\
184*d83cc019SAndroid Build Coastguard Worker 			     tracepoints[tp_id].fields[			\
185*d83cc019SAndroid Build Coastguard Worker 				     tracepoints[tp_id].field_name##_field].offset))
186*d83cc019SAndroid Build Coastguard Worker 
187*d83cc019SAndroid Build Coastguard Worker #define GET_RING_ID(sample, tp_id) \
188*d83cc019SAndroid Build Coastguard Worker ({ \
189*d83cc019SAndroid Build Coastguard Worker 	unsigned char class, instance, ring; \
190*d83cc019SAndroid Build Coastguard Worker \
191*d83cc019SAndroid Build Coastguard Worker 	class = READ_TP_FIELD_U16(sample, tp_id, class); \
192*d83cc019SAndroid Build Coastguard Worker 	instance = READ_TP_FIELD_U16(sample, tp_id, instance); \
193*d83cc019SAndroid Build Coastguard Worker \
194*d83cc019SAndroid Build Coastguard Worker 	assert(class <= I915_ENGINE_CLASS_VIDEO_ENHANCE); \
195*d83cc019SAndroid Build Coastguard Worker 	assert(instance <= 4); \
196*d83cc019SAndroid Build Coastguard Worker \
197*d83cc019SAndroid Build Coastguard Worker 	ring = class * 4 + instance; \
198*d83cc019SAndroid Build Coastguard Worker \
199*d83cc019SAndroid Build Coastguard Worker 	ring; \
200*d83cc019SAndroid Build Coastguard Worker })
201*d83cc019SAndroid Build Coastguard Worker 
perf_tracepoint_open(struct gpu_perf * gp,int tp_id,int (* func)(struct gpu_perf *,const void *))202*d83cc019SAndroid Build Coastguard Worker static int perf_tracepoint_open(struct gpu_perf *gp, int tp_id,
203*d83cc019SAndroid Build Coastguard Worker 				int (*func)(struct gpu_perf *, const void *))
204*d83cc019SAndroid Build Coastguard Worker {
205*d83cc019SAndroid Build Coastguard Worker 	struct perf_event_attr attr;
206*d83cc019SAndroid Build Coastguard Worker 	struct gpu_perf_sample *sample;
207*d83cc019SAndroid Build Coastguard Worker 	int n, *fd;
208*d83cc019SAndroid Build Coastguard Worker 
209*d83cc019SAndroid Build Coastguard Worker 	memset(&attr, 0, sizeof (attr));
210*d83cc019SAndroid Build Coastguard Worker 
211*d83cc019SAndroid Build Coastguard Worker 	attr.type = PERF_TYPE_TRACEPOINT;
212*d83cc019SAndroid Build Coastguard Worker 	attr.config = tracepoint_id(tp_id);
213*d83cc019SAndroid Build Coastguard Worker 	if (attr.config == 0)
214*d83cc019SAndroid Build Coastguard Worker 		return ENOENT;
215*d83cc019SAndroid Build Coastguard Worker 
216*d83cc019SAndroid Build Coastguard Worker 	attr.sample_period = 1;
217*d83cc019SAndroid Build Coastguard Worker 	attr.sample_type = (PERF_SAMPLE_TIME | PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_TID | PERF_SAMPLE_RAW);
218*d83cc019SAndroid Build Coastguard Worker 	attr.read_format = PERF_FORMAT_ID;
219*d83cc019SAndroid Build Coastguard Worker 
220*d83cc019SAndroid Build Coastguard Worker 	attr.exclude_guest = 1;
221*d83cc019SAndroid Build Coastguard Worker 
222*d83cc019SAndroid Build Coastguard Worker 	n = gp->nr_cpus * (gp->nr_events+1);
223*d83cc019SAndroid Build Coastguard Worker 	fd = realloc(gp->fd, n*sizeof(int));
224*d83cc019SAndroid Build Coastguard Worker 	sample = realloc(gp->sample, n*sizeof(*gp->sample));
225*d83cc019SAndroid Build Coastguard Worker 	if (fd == NULL || sample == NULL)
226*d83cc019SAndroid Build Coastguard Worker 		return ENOMEM;
227*d83cc019SAndroid Build Coastguard Worker 	gp->fd = fd;
228*d83cc019SAndroid Build Coastguard Worker 	gp->sample = sample;
229*d83cc019SAndroid Build Coastguard Worker 
230*d83cc019SAndroid Build Coastguard Worker 	fd += gp->nr_events * gp->nr_cpus;
231*d83cc019SAndroid Build Coastguard Worker 	sample += gp->nr_events * gp->nr_cpus;
232*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < gp->nr_cpus; n++) {
233*d83cc019SAndroid Build Coastguard Worker 		uint64_t track[2];
234*d83cc019SAndroid Build Coastguard Worker 
235*d83cc019SAndroid Build Coastguard Worker 		fd[n] = perf_event_open(&attr, -1, n, -1, 0);
236*d83cc019SAndroid Build Coastguard Worker 		if (fd[n] == -1)
237*d83cc019SAndroid Build Coastguard Worker 			return errno;
238*d83cc019SAndroid Build Coastguard Worker 
239*d83cc019SAndroid Build Coastguard Worker 		/* read back the event to establish id->tracepoint */
240*d83cc019SAndroid Build Coastguard Worker 		if (read(fd[n], track, sizeof(track)) < 0)
241*d83cc019SAndroid Build Coastguard Worker 			return errno;
242*d83cc019SAndroid Build Coastguard Worker 		sample[n].id = track[1];
243*d83cc019SAndroid Build Coastguard Worker 		sample[n].func = func;
244*d83cc019SAndroid Build Coastguard Worker 	}
245*d83cc019SAndroid Build Coastguard Worker 
246*d83cc019SAndroid Build Coastguard Worker 	gp->nr_events++;
247*d83cc019SAndroid Build Coastguard Worker 	return 0;
248*d83cc019SAndroid Build Coastguard Worker }
249*d83cc019SAndroid Build Coastguard Worker 
perf_mmap(struct gpu_perf * gp)250*d83cc019SAndroid Build Coastguard Worker static int perf_mmap(struct gpu_perf *gp)
251*d83cc019SAndroid Build Coastguard Worker {
252*d83cc019SAndroid Build Coastguard Worker 	int size = (1 + N_PAGES) * gp->page_size;
253*d83cc019SAndroid Build Coastguard Worker 	int *fd, i, j;
254*d83cc019SAndroid Build Coastguard Worker 
255*d83cc019SAndroid Build Coastguard Worker 	gp->map = malloc(sizeof(void *)*gp->nr_cpus);
256*d83cc019SAndroid Build Coastguard Worker 	if (gp->map == NULL)
257*d83cc019SAndroid Build Coastguard Worker 		return ENOMEM;
258*d83cc019SAndroid Build Coastguard Worker 
259*d83cc019SAndroid Build Coastguard Worker 	fd = gp->fd;
260*d83cc019SAndroid Build Coastguard Worker 	for (j = 0; j < gp->nr_cpus; j++) {
261*d83cc019SAndroid Build Coastguard Worker 		gp->map[j] = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd++, 0);
262*d83cc019SAndroid Build Coastguard Worker 		if (gp->map[j] == (void *)-1)
263*d83cc019SAndroid Build Coastguard Worker 			goto err;
264*d83cc019SAndroid Build Coastguard Worker 	}
265*d83cc019SAndroid Build Coastguard Worker 
266*d83cc019SAndroid Build Coastguard Worker 	for (i = 1; i < gp->nr_events; i++) {
267*d83cc019SAndroid Build Coastguard Worker 		for (j = 0; j < gp->nr_cpus; j++)
268*d83cc019SAndroid Build Coastguard Worker 			ioctl(*fd++, PERF_EVENT_IOC_SET_OUTPUT, gp->fd[j]);
269*d83cc019SAndroid Build Coastguard Worker 	}
270*d83cc019SAndroid Build Coastguard Worker 
271*d83cc019SAndroid Build Coastguard Worker 	return 0;
272*d83cc019SAndroid Build Coastguard Worker 
273*d83cc019SAndroid Build Coastguard Worker err:
274*d83cc019SAndroid Build Coastguard Worker 	while (--j > 0)
275*d83cc019SAndroid Build Coastguard Worker 		munmap(gp->map[j], size);
276*d83cc019SAndroid Build Coastguard Worker 	free(gp->map);
277*d83cc019SAndroid Build Coastguard Worker 	gp->map = NULL;
278*d83cc019SAndroid Build Coastguard Worker 	return EINVAL;
279*d83cc019SAndroid Build Coastguard Worker }
280*d83cc019SAndroid Build Coastguard Worker 
get_comm(pid_t pid,char * comm,int len)281*d83cc019SAndroid Build Coastguard Worker static int get_comm(pid_t pid, char *comm, int len)
282*d83cc019SAndroid Build Coastguard Worker {
283*d83cc019SAndroid Build Coastguard Worker 	char filename[1024];
284*d83cc019SAndroid Build Coastguard Worker 	int fd;
285*d83cc019SAndroid Build Coastguard Worker 
286*d83cc019SAndroid Build Coastguard Worker 	*comm = '\0';
287*d83cc019SAndroid Build Coastguard Worker 	snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
288*d83cc019SAndroid Build Coastguard Worker 
289*d83cc019SAndroid Build Coastguard Worker 	fd = open(filename, 0);
290*d83cc019SAndroid Build Coastguard Worker 	if (fd >= 0) {
291*d83cc019SAndroid Build Coastguard Worker 		len = read(fd, comm, len-1);
292*d83cc019SAndroid Build Coastguard Worker 		if (len >= 0)
293*d83cc019SAndroid Build Coastguard Worker 			comm[len-1] = '\0';
294*d83cc019SAndroid Build Coastguard Worker 		close(fd);
295*d83cc019SAndroid Build Coastguard Worker 	} else
296*d83cc019SAndroid Build Coastguard Worker 		len = -1;
297*d83cc019SAndroid Build Coastguard Worker 
298*d83cc019SAndroid Build Coastguard Worker 	return len;
299*d83cc019SAndroid Build Coastguard Worker }
300*d83cc019SAndroid Build Coastguard Worker 
301*d83cc019SAndroid Build Coastguard Worker static struct gpu_perf_comm *
lookup_comm(struct gpu_perf * gp,pid_t pid)302*d83cc019SAndroid Build Coastguard Worker lookup_comm(struct gpu_perf *gp, pid_t pid)
303*d83cc019SAndroid Build Coastguard Worker {
304*d83cc019SAndroid Build Coastguard Worker 	struct gpu_perf_comm *comm;
305*d83cc019SAndroid Build Coastguard Worker 
306*d83cc019SAndroid Build Coastguard Worker 	if (pid == 0)
307*d83cc019SAndroid Build Coastguard Worker 		return NULL;
308*d83cc019SAndroid Build Coastguard Worker 
309*d83cc019SAndroid Build Coastguard Worker 	for (comm = gp->comm; comm != NULL; comm = comm->next) {
310*d83cc019SAndroid Build Coastguard Worker 		if (comm->pid == pid)
311*d83cc019SAndroid Build Coastguard Worker 			break;
312*d83cc019SAndroid Build Coastguard Worker 	}
313*d83cc019SAndroid Build Coastguard Worker 	if (comm == NULL) {
314*d83cc019SAndroid Build Coastguard Worker 		comm = calloc(1, sizeof(*comm));
315*d83cc019SAndroid Build Coastguard Worker 		if (comm == NULL)
316*d83cc019SAndroid Build Coastguard Worker 			return NULL;
317*d83cc019SAndroid Build Coastguard Worker 
318*d83cc019SAndroid Build Coastguard Worker 		if (get_comm(pid, comm->name, sizeof(comm->name)) < 0) {
319*d83cc019SAndroid Build Coastguard Worker 			free(comm);
320*d83cc019SAndroid Build Coastguard Worker 			return NULL;
321*d83cc019SAndroid Build Coastguard Worker 		}
322*d83cc019SAndroid Build Coastguard Worker 
323*d83cc019SAndroid Build Coastguard Worker 		comm->pid = pid;
324*d83cc019SAndroid Build Coastguard Worker 		comm->next = gp->comm;
325*d83cc019SAndroid Build Coastguard Worker 		gp->comm = comm;
326*d83cc019SAndroid Build Coastguard Worker 	}
327*d83cc019SAndroid Build Coastguard Worker 
328*d83cc019SAndroid Build Coastguard Worker 	return comm;
329*d83cc019SAndroid Build Coastguard Worker }
330*d83cc019SAndroid Build Coastguard Worker 
request_add(struct gpu_perf * gp,const void * event)331*d83cc019SAndroid Build Coastguard Worker static int request_add(struct gpu_perf *gp, const void *event)
332*d83cc019SAndroid Build Coastguard Worker {
333*d83cc019SAndroid Build Coastguard Worker 	const struct sample_event *sample = event;
334*d83cc019SAndroid Build Coastguard Worker 	struct gpu_perf_comm *comm;
335*d83cc019SAndroid Build Coastguard Worker 
336*d83cc019SAndroid Build Coastguard Worker 	comm = lookup_comm(gp, sample->pid);
337*d83cc019SAndroid Build Coastguard Worker 	if (comm == NULL)
338*d83cc019SAndroid Build Coastguard Worker 		return 0;
339*d83cc019SAndroid Build Coastguard Worker 
340*d83cc019SAndroid Build Coastguard Worker 	comm->nr_requests[GET_RING_ID(sample, TP_GEM_REQUEST_ADD)]++;
341*d83cc019SAndroid Build Coastguard Worker 	return 1;
342*d83cc019SAndroid Build Coastguard Worker }
343*d83cc019SAndroid Build Coastguard Worker 
flip_complete(struct gpu_perf * gp,const void * event)344*d83cc019SAndroid Build Coastguard Worker static int flip_complete(struct gpu_perf *gp, const void *event)
345*d83cc019SAndroid Build Coastguard Worker {
346*d83cc019SAndroid Build Coastguard Worker 	const struct sample_event *sample = event;
347*d83cc019SAndroid Build Coastguard Worker 
348*d83cc019SAndroid Build Coastguard Worker 	gp->flip_complete[READ_TP_FIELD_U32(sample, TP_FLIP_COMPLETE, plane)]++;
349*d83cc019SAndroid Build Coastguard Worker 	return 1;
350*d83cc019SAndroid Build Coastguard Worker }
351*d83cc019SAndroid Build Coastguard Worker 
ctx_switch(struct gpu_perf * gp,const void * event)352*d83cc019SAndroid Build Coastguard Worker static int ctx_switch(struct gpu_perf *gp, const void *event)
353*d83cc019SAndroid Build Coastguard Worker {
354*d83cc019SAndroid Build Coastguard Worker 	const struct sample_event *sample = event;
355*d83cc019SAndroid Build Coastguard Worker 
356*d83cc019SAndroid Build Coastguard Worker 	gp->ctx_switch[GET_RING_ID(sample, TP_GEM_RING_SWITCH_CONTEXT)]++;
357*d83cc019SAndroid Build Coastguard Worker 	return 1;
358*d83cc019SAndroid Build Coastguard Worker }
359*d83cc019SAndroid Build Coastguard Worker 
ring_sync(struct gpu_perf * gp,const void * event)360*d83cc019SAndroid Build Coastguard Worker static int ring_sync(struct gpu_perf *gp, const void *event)
361*d83cc019SAndroid Build Coastguard Worker {
362*d83cc019SAndroid Build Coastguard Worker 	const struct sample_event *sample = event;
363*d83cc019SAndroid Build Coastguard Worker 	struct gpu_perf_comm *comm;
364*d83cc019SAndroid Build Coastguard Worker 
365*d83cc019SAndroid Build Coastguard Worker 	comm = lookup_comm(gp, sample->pid);
366*d83cc019SAndroid Build Coastguard Worker 	if (comm == NULL)
367*d83cc019SAndroid Build Coastguard Worker 		return 0;
368*d83cc019SAndroid Build Coastguard Worker 
369*d83cc019SAndroid Build Coastguard Worker 	comm->nr_sema++;
370*d83cc019SAndroid Build Coastguard Worker 	return 1;
371*d83cc019SAndroid Build Coastguard Worker }
372*d83cc019SAndroid Build Coastguard Worker 
wait_begin(struct gpu_perf * gp,const void * event)373*d83cc019SAndroid Build Coastguard Worker static int wait_begin(struct gpu_perf *gp, const void *event)
374*d83cc019SAndroid Build Coastguard Worker {
375*d83cc019SAndroid Build Coastguard Worker 	const struct sample_event *sample = event;
376*d83cc019SAndroid Build Coastguard Worker 	struct gpu_perf_comm *comm;
377*d83cc019SAndroid Build Coastguard Worker 	struct gpu_perf_time *wait;
378*d83cc019SAndroid Build Coastguard Worker 
379*d83cc019SAndroid Build Coastguard Worker 	comm = lookup_comm(gp, sample->pid);
380*d83cc019SAndroid Build Coastguard Worker 	if (comm == NULL)
381*d83cc019SAndroid Build Coastguard Worker 		return 0;
382*d83cc019SAndroid Build Coastguard Worker 
383*d83cc019SAndroid Build Coastguard Worker 	wait = malloc(sizeof(*wait));
384*d83cc019SAndroid Build Coastguard Worker 	if (wait == NULL)
385*d83cc019SAndroid Build Coastguard Worker 		return 0;
386*d83cc019SAndroid Build Coastguard Worker 
387*d83cc019SAndroid Build Coastguard Worker 	/* XXX argument order CTX == ENGINE! */
388*d83cc019SAndroid Build Coastguard Worker 
389*d83cc019SAndroid Build Coastguard Worker 	wait->comm = comm;
390*d83cc019SAndroid Build Coastguard Worker 	wait->comm->active = true;
391*d83cc019SAndroid Build Coastguard Worker 	wait->context = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_BEGIN, ctx);
392*d83cc019SAndroid Build Coastguard Worker 	wait->seqno = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_BEGIN, seqno);
393*d83cc019SAndroid Build Coastguard Worker 	wait->time = sample->time;
394*d83cc019SAndroid Build Coastguard Worker 	wait->next = gp->wait[GET_RING_ID(sample, TP_GEM_REQUEST_WAIT_BEGIN)];
395*d83cc019SAndroid Build Coastguard Worker 	gp->wait[GET_RING_ID(sample, TP_GEM_REQUEST_WAIT_BEGIN)] = wait;
396*d83cc019SAndroid Build Coastguard Worker 
397*d83cc019SAndroid Build Coastguard Worker 	return 0;
398*d83cc019SAndroid Build Coastguard Worker }
399*d83cc019SAndroid Build Coastguard Worker 
wait_end(struct gpu_perf * gp,const void * event)400*d83cc019SAndroid Build Coastguard Worker static int wait_end(struct gpu_perf *gp, const void *event)
401*d83cc019SAndroid Build Coastguard Worker {
402*d83cc019SAndroid Build Coastguard Worker 	const struct sample_event *sample = event;
403*d83cc019SAndroid Build Coastguard Worker 	struct gpu_perf_time *wait, **prev;
404*d83cc019SAndroid Build Coastguard Worker 	uint32_t engine = GET_RING_ID(sample, TP_GEM_REQUEST_WAIT_END);
405*d83cc019SAndroid Build Coastguard Worker 	uint32_t context = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_END, ctx);
406*d83cc019SAndroid Build Coastguard Worker 	uint32_t seqno = READ_TP_FIELD_U32(sample, TP_GEM_REQUEST_WAIT_END, seqno);
407*d83cc019SAndroid Build Coastguard Worker 
408*d83cc019SAndroid Build Coastguard Worker 	for (prev = &gp->wait[engine]; (wait = *prev) != NULL; prev = &wait->next) {
409*d83cc019SAndroid Build Coastguard Worker 		if (wait->context != context || wait->seqno != seqno)
410*d83cc019SAndroid Build Coastguard Worker 			continue;
411*d83cc019SAndroid Build Coastguard Worker 
412*d83cc019SAndroid Build Coastguard Worker 		wait->comm->wait_time += sample->time - wait->time;
413*d83cc019SAndroid Build Coastguard Worker 		wait->comm->active = false;
414*d83cc019SAndroid Build Coastguard Worker 
415*d83cc019SAndroid Build Coastguard Worker 		*prev = wait->next;
416*d83cc019SAndroid Build Coastguard Worker 		free(wait);
417*d83cc019SAndroid Build Coastguard Worker 		return 1;
418*d83cc019SAndroid Build Coastguard Worker 	}
419*d83cc019SAndroid Build Coastguard Worker 
420*d83cc019SAndroid Build Coastguard Worker 	return 0;
421*d83cc019SAndroid Build Coastguard Worker }
422*d83cc019SAndroid Build Coastguard Worker 
gpu_perf_init(struct gpu_perf * gp,unsigned flags)423*d83cc019SAndroid Build Coastguard Worker void gpu_perf_init(struct gpu_perf *gp, unsigned flags)
424*d83cc019SAndroid Build Coastguard Worker {
425*d83cc019SAndroid Build Coastguard Worker 	memset(gp, 0, sizeof(*gp));
426*d83cc019SAndroid Build Coastguard Worker 	gp->nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
427*d83cc019SAndroid Build Coastguard Worker 	gp->page_size = getpagesize();
428*d83cc019SAndroid Build Coastguard Worker 
429*d83cc019SAndroid Build Coastguard Worker 	perf_tracepoint_open(gp, TP_GEM_REQUEST_ADD, request_add);
430*d83cc019SAndroid Build Coastguard Worker 	if (perf_tracepoint_open(gp, TP_GEM_REQUEST_WAIT_BEGIN, wait_begin) == 0)
431*d83cc019SAndroid Build Coastguard Worker 		perf_tracepoint_open(gp, TP_GEM_REQUEST_WAIT_END, wait_end);
432*d83cc019SAndroid Build Coastguard Worker 	perf_tracepoint_open(gp, TP_FLIP_COMPLETE, flip_complete);
433*d83cc019SAndroid Build Coastguard Worker 	perf_tracepoint_open(gp, TP_GEM_RING_SYNC_TO, ring_sync);
434*d83cc019SAndroid Build Coastguard Worker 	perf_tracepoint_open(gp, TP_GEM_RING_SWITCH_CONTEXT, ctx_switch);
435*d83cc019SAndroid Build Coastguard Worker 
436*d83cc019SAndroid Build Coastguard Worker 	if (gp->nr_events == 0) {
437*d83cc019SAndroid Build Coastguard Worker 		gp->error = "i915.ko tracepoints not available";
438*d83cc019SAndroid Build Coastguard Worker 		return;
439*d83cc019SAndroid Build Coastguard Worker 	}
440*d83cc019SAndroid Build Coastguard Worker 
441*d83cc019SAndroid Build Coastguard Worker 	if (perf_mmap(gp))
442*d83cc019SAndroid Build Coastguard Worker 		return;
443*d83cc019SAndroid Build Coastguard Worker }
444*d83cc019SAndroid Build Coastguard Worker 
process_sample(struct gpu_perf * gp,int cpu,const struct perf_event_header * header)445*d83cc019SAndroid Build Coastguard Worker static int process_sample(struct gpu_perf *gp, int cpu,
446*d83cc019SAndroid Build Coastguard Worker 			  const struct perf_event_header *header)
447*d83cc019SAndroid Build Coastguard Worker {
448*d83cc019SAndroid Build Coastguard Worker 	const struct sample_event *sample = (const struct sample_event *)header;
449*d83cc019SAndroid Build Coastguard Worker 	int n, update = 0;
450*d83cc019SAndroid Build Coastguard Worker 
451*d83cc019SAndroid Build Coastguard Worker 	/* hash me! */
452*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < gp->nr_events; n++) {
453*d83cc019SAndroid Build Coastguard Worker 		int m = n * gp->nr_cpus + cpu;
454*d83cc019SAndroid Build Coastguard Worker 		if (gp->sample[m].id != sample->id)
455*d83cc019SAndroid Build Coastguard Worker 			continue;
456*d83cc019SAndroid Build Coastguard Worker 
457*d83cc019SAndroid Build Coastguard Worker 		update = gp->sample[m].func(gp, sample);
458*d83cc019SAndroid Build Coastguard Worker 		break;
459*d83cc019SAndroid Build Coastguard Worker 	}
460*d83cc019SAndroid Build Coastguard Worker 
461*d83cc019SAndroid Build Coastguard Worker 	return update;
462*d83cc019SAndroid Build Coastguard Worker }
463*d83cc019SAndroid Build Coastguard Worker 
gpu_perf_update(struct gpu_perf * gp)464*d83cc019SAndroid Build Coastguard Worker int gpu_perf_update(struct gpu_perf *gp)
465*d83cc019SAndroid Build Coastguard Worker {
466*d83cc019SAndroid Build Coastguard Worker 	const int size = N_PAGES * gp->page_size;
467*d83cc019SAndroid Build Coastguard Worker 	const int mask = size - 1;
468*d83cc019SAndroid Build Coastguard Worker 	uint8_t *buffer = NULL;
469*d83cc019SAndroid Build Coastguard Worker 	int buffer_size = 0;
470*d83cc019SAndroid Build Coastguard Worker 	int n, update = 0;
471*d83cc019SAndroid Build Coastguard Worker 
472*d83cc019SAndroid Build Coastguard Worker 	if (gp->map == NULL)
473*d83cc019SAndroid Build Coastguard Worker 		return 0;
474*d83cc019SAndroid Build Coastguard Worker 
475*d83cc019SAndroid Build Coastguard Worker 	for (n = 0; n < gp->nr_cpus; n++) {
476*d83cc019SAndroid Build Coastguard Worker 		struct perf_event_mmap_page *mmap = gp->map[n];
477*d83cc019SAndroid Build Coastguard Worker 		const uint8_t *data;
478*d83cc019SAndroid Build Coastguard Worker 		uint64_t head, tail;
479*d83cc019SAndroid Build Coastguard Worker 		int wrap = 0;
480*d83cc019SAndroid Build Coastguard Worker 
481*d83cc019SAndroid Build Coastguard Worker 		tail = mmap->data_tail;
482*d83cc019SAndroid Build Coastguard Worker 		head = mmap->data_head;
483*d83cc019SAndroid Build Coastguard Worker 		rmb();
484*d83cc019SAndroid Build Coastguard Worker 
485*d83cc019SAndroid Build Coastguard Worker 		if (head < tail) {
486*d83cc019SAndroid Build Coastguard Worker 			wrap = 1;
487*d83cc019SAndroid Build Coastguard Worker 			tail &= mask;
488*d83cc019SAndroid Build Coastguard Worker 			head &= mask;
489*d83cc019SAndroid Build Coastguard Worker 			head += size;
490*d83cc019SAndroid Build Coastguard Worker 		}
491*d83cc019SAndroid Build Coastguard Worker 
492*d83cc019SAndroid Build Coastguard Worker 		data = (uint8_t *)mmap + gp->page_size;
493*d83cc019SAndroid Build Coastguard Worker 		while (head - tail >= sizeof (struct perf_event_header)) {
494*d83cc019SAndroid Build Coastguard Worker 			const struct perf_event_header *header;
495*d83cc019SAndroid Build Coastguard Worker 
496*d83cc019SAndroid Build Coastguard Worker 			header = (const struct perf_event_header *)(data + (tail & mask));
497*d83cc019SAndroid Build Coastguard Worker 			assert(header->size > 0);
498*d83cc019SAndroid Build Coastguard Worker 			if (header->size > head - tail)
499*d83cc019SAndroid Build Coastguard Worker 				break;
500*d83cc019SAndroid Build Coastguard Worker 
501*d83cc019SAndroid Build Coastguard Worker 			if ((const uint8_t *)header + header->size > data + size) {
502*d83cc019SAndroid Build Coastguard Worker 				int before;
503*d83cc019SAndroid Build Coastguard Worker 
504*d83cc019SAndroid Build Coastguard Worker 				if (header->size > buffer_size) {
505*d83cc019SAndroid Build Coastguard Worker 					uint8_t *b = realloc(buffer, header->size);
506*d83cc019SAndroid Build Coastguard Worker 					if (b == NULL)
507*d83cc019SAndroid Build Coastguard Worker 						break;
508*d83cc019SAndroid Build Coastguard Worker 
509*d83cc019SAndroid Build Coastguard Worker 					buffer = b;
510*d83cc019SAndroid Build Coastguard Worker 					buffer_size = header->size;
511*d83cc019SAndroid Build Coastguard Worker 				}
512*d83cc019SAndroid Build Coastguard Worker 
513*d83cc019SAndroid Build Coastguard Worker 				before = data + size - (const uint8_t *)header;
514*d83cc019SAndroid Build Coastguard Worker 
515*d83cc019SAndroid Build Coastguard Worker 				memcpy(buffer, header, before);
516*d83cc019SAndroid Build Coastguard Worker 				memcpy(buffer + before, data, header->size - before);
517*d83cc019SAndroid Build Coastguard Worker 
518*d83cc019SAndroid Build Coastguard Worker 				header = (struct perf_event_header *)buffer;
519*d83cc019SAndroid Build Coastguard Worker 			}
520*d83cc019SAndroid Build Coastguard Worker 
521*d83cc019SAndroid Build Coastguard Worker 			if (header->type == PERF_RECORD_SAMPLE)
522*d83cc019SAndroid Build Coastguard Worker 				update += process_sample(gp, n, header);
523*d83cc019SAndroid Build Coastguard Worker 			tail += header->size;
524*d83cc019SAndroid Build Coastguard Worker 		}
525*d83cc019SAndroid Build Coastguard Worker 
526*d83cc019SAndroid Build Coastguard Worker 		if (wrap)
527*d83cc019SAndroid Build Coastguard Worker 			tail &= mask;
528*d83cc019SAndroid Build Coastguard Worker 		mmap->data_tail = tail;
529*d83cc019SAndroid Build Coastguard Worker 		wmb();
530*d83cc019SAndroid Build Coastguard Worker 	}
531*d83cc019SAndroid Build Coastguard Worker 
532*d83cc019SAndroid Build Coastguard Worker 	free(buffer);
533*d83cc019SAndroid Build Coastguard Worker 	return update;
534*d83cc019SAndroid Build Coastguard Worker }
535