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