blob: 8ee29b5d8916b2c5fc62e9b9efbdcd6f9f44b015 [file] [log] [blame]
Chris Wilson0393e722015-08-09 17:39:41 +01001/*
2 * Copyright © 2015 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
Chris Wilson0393e722015-08-09 17:39:41 +010024#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <stdint.h>
28#include <stdbool.h>
29#include <stdarg.h>
30#include <fcntl.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <unistd.h>
35#include <errno.h>
36#include <sys/mman.h>
37#include <dlfcn.h>
38#include <i915_drm.h>
Chris Wilsonf6256cd2017-03-28 15:11:26 +010039#include <pthread.h>
Chris Wilson0393e722015-08-09 17:39:41 +010040
41#include "intel_aub.h"
42#include "intel_chipset.h"
43
44static int (*libc_close)(int fd);
45static int (*libc_ioctl)(int fd, unsigned long request, void *argp);
46
Chris Wilsonf6256cd2017-03-28 15:11:26 +010047static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
48
Chris Wilson49e09e72017-03-28 11:26:39 +010049struct trace {
50 int fd;
51 FILE *file;
52 struct trace *next;
53} *traces;
Chris Wilson0393e722015-08-09 17:39:41 +010054
55#define DRM_MAJOR 226
56
57enum {
58 ADD_BO = 0,
59 DEL_BO,
Chris Wilson49e09e72017-03-28 11:26:39 +010060 ADD_CTX,
61 DEL_CTX,
Chris Wilson0393e722015-08-09 17:39:41 +010062 EXEC,
Chris Wilson4bf3ca82017-03-28 13:12:24 +010063 WAIT,
Chris Wilson0393e722015-08-09 17:39:41 +010064};
65
Chris Wilson49e09e72017-03-28 11:26:39 +010066static struct trace_verion {
67 uint32_t magic;
68 uint32_t version;
69} version = {
70 .magic = 0xdeadbeef,
71 .version = 1
72};
73
Chris Wilson0393e722015-08-09 17:39:41 +010074struct trace_add_bo {
75 uint8_t cmd;
76 uint32_t handle;
77 uint64_t size;
78} __attribute__((packed));
79struct trace_del_bo {
80 uint8_t cmd;
81 uint32_t handle;
82}__attribute__((packed));
83
Chris Wilson49e09e72017-03-28 11:26:39 +010084struct trace_add_ctx {
85 uint8_t cmd;
86 uint32_t handle;
87} __attribute__((packed));
88struct trace_del_ctx {
89 uint8_t cmd;
90 uint32_t handle;
91}__attribute__((packed));
92
Chris Wilson0393e722015-08-09 17:39:41 +010093struct trace_exec {
94 uint8_t cmd;
95 uint32_t object_count;
96 uint64_t flags;
Chris Wilson49e09e72017-03-28 11:26:39 +010097 uint32_t context;
Chris Wilson0393e722015-08-09 17:39:41 +010098}__attribute__((packed));
99
100struct trace_exec_object {
101 uint32_t handle;
102 uint32_t relocation_count;
103 uint64_t alignment;
Chris Wilson49e09e72017-03-28 11:26:39 +0100104 uint64_t offset;
Chris Wilson0393e722015-08-09 17:39:41 +0100105 uint64_t flags;
106 uint64_t rsvd1;
107 uint64_t rsvd2;
108}__attribute__((packed));
109
110struct trace_exec_relocation {
111 uint32_t target_handle;
112 uint32_t delta;
113 uint64_t offset;
Chris Wilson49e09e72017-03-28 11:26:39 +0100114 uint64_t presumed_offset;
Chris Wilson0393e722015-08-09 17:39:41 +0100115 uint32_t read_domains;
116 uint32_t write_domain;
117}__attribute__((packed));
118
Chris Wilson4bf3ca82017-03-28 13:12:24 +0100119struct trace_wait {
120 uint8_t cmd;
121 uint32_t handle;
122} __attribute__((packed));
123
Chris Wilson0393e722015-08-09 17:39:41 +0100124static void __attribute__ ((format(__printf__, 2, 3)))
125fail_if(int cond, const char *format, ...)
126{
127 va_list args;
128
129 if (!cond)
130 return;
131
132 va_start(args, format);
133 vfprintf(stderr, format, args);
134 va_end(args);
135
Chris Wilson49e09e72017-03-28 11:26:39 +0100136 abort();
Chris Wilson0393e722015-08-09 17:39:41 +0100137}
138
Arkadiusz Hiler6e572cf2017-07-11 13:51:01 +0300139#define LOCAL_I915_EXEC_FENCE_IN (1<<16)
140#define LOCAL_I915_EXEC_FENCE_OUT (1<<17)
141
Chris Wilson0393e722015-08-09 17:39:41 +0100142static void
Chris Wilson49e09e72017-03-28 11:26:39 +0100143trace_exec(struct trace *trace,
144 const struct drm_i915_gem_execbuffer2 *execbuffer2)
Chris Wilson0393e722015-08-09 17:39:41 +0100145{
Chris Wilson49e09e72017-03-28 11:26:39 +0100146#define to_ptr(T, x) ((T *)(uintptr_t)(x))
Chris Wilson0393e722015-08-09 17:39:41 +0100147 const struct drm_i915_gem_exec_object2 *exec_objects =
Chris Wilson49e09e72017-03-28 11:26:39 +0100148 to_ptr(typeof(*exec_objects), execbuffer2->buffers_ptr);
149
Arkadiusz Hiler6e572cf2017-07-11 13:51:01 +0300150 fail_if(execbuffer2->flags & (LOCAL_I915_EXEC_FENCE_IN | LOCAL_I915_EXEC_FENCE_OUT),
Chris Wilson49e09e72017-03-28 11:26:39 +0100151 "fences not supported yet\n");
Chris Wilson0393e722015-08-09 17:39:41 +0100152
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100153 flockfile(trace->file);
Chris Wilson0393e722015-08-09 17:39:41 +0100154 {
155 struct trace_exec t = {
Chris Wilson49e09e72017-03-28 11:26:39 +0100156 EXEC,
157 execbuffer2->buffer_count,
158 execbuffer2->flags,
159 execbuffer2->rsvd1,
Chris Wilson39116212015-08-10 18:17:47 +0100160 };
Chris Wilson49e09e72017-03-28 11:26:39 +0100161 fwrite(&t, sizeof(t), 1, trace->file);
Chris Wilson0393e722015-08-09 17:39:41 +0100162 }
163
164 for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) {
165 const struct drm_i915_gem_exec_object2 *obj = &exec_objects[i];
166 const struct drm_i915_gem_relocation_entry *relocs =
Chris Wilson49e09e72017-03-28 11:26:39 +0100167 to_ptr(typeof(*relocs), obj->relocs_ptr);
Chris Wilson0393e722015-08-09 17:39:41 +0100168 {
169 struct trace_exec_object t = {
170 obj->handle,
171 obj->relocation_count,
172 obj->alignment,
Chris Wilson49e09e72017-03-28 11:26:39 +0100173 obj->offset,
Chris Wilson0393e722015-08-09 17:39:41 +0100174 obj->flags,
175 obj->rsvd1,
176 obj->rsvd2
177 };
Chris Wilson49e09e72017-03-28 11:26:39 +0100178 fwrite(&t, sizeof(t), 1, trace->file);
Chris Wilson0393e722015-08-09 17:39:41 +0100179 }
Chris Wilson49e09e72017-03-28 11:26:39 +0100180 fwrite(relocs, sizeof(*relocs), obj->relocation_count,
181 trace->file);
Chris Wilson0393e722015-08-09 17:39:41 +0100182 }
183
Chris Wilson49e09e72017-03-28 11:26:39 +0100184 fflush(trace->file);
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100185 funlockfile(trace->file);
Chris Wilson49e09e72017-03-28 11:26:39 +0100186#undef to_ptr
Chris Wilson0393e722015-08-09 17:39:41 +0100187}
188
189static void
Chris Wilson4bf3ca82017-03-28 13:12:24 +0100190trace_wait(struct trace *trace, uint32_t handle)
191{
192 struct trace_wait t = { WAIT, handle };
193 fwrite(&t, sizeof(t), 1, trace->file);
194}
195
196static void
Chris Wilson49e09e72017-03-28 11:26:39 +0100197trace_add(struct trace *trace, uint32_t handle, uint64_t size)
Chris Wilson0393e722015-08-09 17:39:41 +0100198{
199 struct trace_add_bo t = { ADD_BO, handle, size };
Chris Wilson49e09e72017-03-28 11:26:39 +0100200 fwrite(&t, sizeof(t), 1, trace->file);
Chris Wilson0393e722015-08-09 17:39:41 +0100201}
202
203static void
Chris Wilson49e09e72017-03-28 11:26:39 +0100204trace_del(struct trace *trace, uint32_t handle)
Chris Wilson0393e722015-08-09 17:39:41 +0100205{
206 struct trace_del_bo t = { DEL_BO, handle };
Chris Wilson49e09e72017-03-28 11:26:39 +0100207 fwrite(&t, sizeof(t), 1, trace->file);
208}
209
210static void
211trace_add_context(struct trace *trace, uint32_t handle)
212{
213 struct trace_add_ctx t = { ADD_CTX, handle };
214 fwrite(&t, sizeof(t), 1, trace->file);
215}
216
217static void
218trace_del_context(struct trace *trace, uint32_t handle)
219{
220 struct trace_del_ctx t = { DEL_CTX, handle };
221 fwrite(&t, sizeof(t), 1, trace->file);
Chris Wilson0393e722015-08-09 17:39:41 +0100222}
223
224int
225close(int fd)
226{
Chris Wilson49e09e72017-03-28 11:26:39 +0100227 struct trace *t, **p;
228
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100229 pthread_mutex_lock(&mutex);
Chris Wilson49e09e72017-03-28 11:26:39 +0100230 for (p = &traces; (t = *p); p = &t->next) {
231 if (t->fd == fd) {
232 *p = t->next;
233 fclose(t->file);
234 free(t);
235 break;
236 }
237 }
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100238 pthread_mutex_unlock(&mutex);
Chris Wilson0393e722015-08-09 17:39:41 +0100239
240 return libc_close(fd);
241}
242
Chris Wilsona64e6c32015-08-14 20:31:48 +0100243static unsigned long
244size_for_fb(const struct drm_mode_fb_cmd *cmd)
245{
246 unsigned long size;
247
248#ifndef ALIGN
249#define ALIGN(x, y) (((x) + (y) - 1) & -(y))
250#endif
251
252 size = ALIGN(cmd->width * cmd->bpp, 64);
253 size *= cmd->height;
254 return ALIGN(size, 4096);
255}
256
257static int is_i915(int fd)
258{
Chris Wilson49e09e72017-03-28 11:26:39 +0100259 drm_version_t v;
Chris Wilsona64e6c32015-08-14 20:31:48 +0100260 char name[5] = "";
261
Chris Wilson49e09e72017-03-28 11:26:39 +0100262 memset(&v, 0, sizeof(v));
263 v.name_len = 4;
264 v.name = name;
Chris Wilsona64e6c32015-08-14 20:31:48 +0100265
Chris Wilson49e09e72017-03-28 11:26:39 +0100266 if (libc_ioctl(fd, DRM_IOCTL_VERSION, &v))
Chris Wilsona64e6c32015-08-14 20:31:48 +0100267 return 0;
268
269 return strcmp(name, "i915") == 0;
270}
271
Arkadiusz Hiler6e572cf2017-07-11 13:51:01 +0300272#define LOCAL_IOCTL_I915_GEM_EXECBUFFER2_WR \
273 DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2)
274
Chris Wilson0393e722015-08-09 17:39:41 +0100275int
276ioctl(int fd, unsigned long request, ...)
277{
Chris Wilson49e09e72017-03-28 11:26:39 +0100278 struct trace *t, **p;
Chris Wilson0393e722015-08-09 17:39:41 +0100279 va_list args;
280 void *argp;
281 int ret;
282
283 va_start(args, request);
284 argp = va_arg(args, void *);
285 va_end(args);
286
Chris Wilsona64e6c32015-08-14 20:31:48 +0100287 if (_IOC_TYPE(request) != DRM_IOCTL_BASE)
Chris Wilson49e09e72017-03-28 11:26:39 +0100288 goto untraced;
Chris Wilsona64e6c32015-08-14 20:31:48 +0100289
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100290 pthread_mutex_lock(&mutex);
Chris Wilson49e09e72017-03-28 11:26:39 +0100291 for (p = &traces; (t = *p); p = &t->next) {
292 if (fd == t->fd) {
293 if (traces != t) {
294 *p = t->next;
295 t->next = traces;
296 traces = t;
297 }
298 break;
299 }
300 }
301 if (!t) {
Chris Wilson0393e722015-08-09 17:39:41 +0100302 char filename[80];
Chris Wilsona64e6c32015-08-14 20:31:48 +0100303
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100304 if (!is_i915(fd)) {
305 pthread_mutex_unlock(&mutex);
Chris Wilson49e09e72017-03-28 11:26:39 +0100306 goto untraced;
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100307 }
Chris Wilsona64e6c32015-08-14 20:31:48 +0100308
Chris Wilson49e09e72017-03-28 11:26:39 +0100309 t = malloc(sizeof(*t));
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100310 if (!t) {
311 pthread_mutex_unlock(&mutex);
Chris Wilson49e09e72017-03-28 11:26:39 +0100312 return -ENOMEM;
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100313 }
Chris Wilsona64e6c32015-08-14 20:31:48 +0100314
Chris Wilson49e09e72017-03-28 11:26:39 +0100315 sprintf(filename, "/tmp/trace-%d.%d", getpid(), fd);
316 t->file = fopen(filename, "w+");
317 t->fd = fd;
318
319 if (!fwrite(&version, sizeof(version), 1, t->file)) {
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100320 pthread_mutex_unlock(&mutex);
Chris Wilson49e09e72017-03-28 11:26:39 +0100321 fclose(t->file);
322 free(t);
323 return -ENOMEM;
324 }
325
326 t->next = traces;
327 traces = t;
Chris Wilson0393e722015-08-09 17:39:41 +0100328 }
Chris Wilsonf6256cd2017-03-28 15:11:26 +0100329 pthread_mutex_unlock(&mutex);
Chris Wilson0393e722015-08-09 17:39:41 +0100330
Chris Wilsona64e6c32015-08-14 20:31:48 +0100331 switch (request) {
332 case DRM_IOCTL_I915_GEM_EXECBUFFER2:
Arkadiusz Hiler6e572cf2017-07-11 13:51:01 +0300333 case LOCAL_IOCTL_I915_GEM_EXECBUFFER2_WR:
Chris Wilson49e09e72017-03-28 11:26:39 +0100334 trace_exec(t, argp);
Chris Wilsona64e6c32015-08-14 20:31:48 +0100335 break;
Chris Wilson0393e722015-08-09 17:39:41 +0100336
Chris Wilson49e09e72017-03-28 11:26:39 +0100337 case DRM_IOCTL_GEM_CLOSE: {
338 struct drm_gem_close *close = argp;
339 trace_del(t, close->handle);
340 break;
341 }
342
343 case DRM_IOCTL_I915_GEM_CONTEXT_DESTROY: {
344 struct drm_i915_gem_context_destroy *close = argp;
345 trace_del_context(t, close->ctx_id);
346 break;
347 }
Chris Wilson4bf3ca82017-03-28 13:12:24 +0100348
349 case DRM_IOCTL_I915_GEM_WAIT: {
350 struct drm_i915_gem_wait *w = argp;
351 trace_wait(t, w->bo_handle);
352 break;
353 }
354
355 case DRM_IOCTL_I915_GEM_SET_DOMAIN: {
356 struct drm_i915_gem_set_domain *w = argp;
357 trace_wait(t, w->handle);
358 break;
359 }
Chris Wilson49e09e72017-03-28 11:26:39 +0100360 }
361
362 ret = libc_ioctl(fd, request, argp);
363 if (ret)
364 return ret;
365
366 switch (request) {
Chris Wilsona64e6c32015-08-14 20:31:48 +0100367 case DRM_IOCTL_I915_GEM_CREATE: {
368 struct drm_i915_gem_create *create = argp;
Chris Wilson49e09e72017-03-28 11:26:39 +0100369 trace_add(t, create->handle, create->size);
Chris Wilsona64e6c32015-08-14 20:31:48 +0100370 break;
Chris Wilson0393e722015-08-09 17:39:41 +0100371 }
Chris Wilsona64e6c32015-08-14 20:31:48 +0100372
373 case DRM_IOCTL_I915_GEM_USERPTR: {
374 struct drm_i915_gem_userptr *userptr = argp;
Chris Wilson49e09e72017-03-28 11:26:39 +0100375 trace_add(t, userptr->handle, userptr->user_size);
Chris Wilsona64e6c32015-08-14 20:31:48 +0100376 break;
377 }
378
379 case DRM_IOCTL_GEM_OPEN: {
380 struct drm_gem_open *open = argp;
Chris Wilson49e09e72017-03-28 11:26:39 +0100381 trace_add(t, open->handle, open->size);
Chris Wilsona64e6c32015-08-14 20:31:48 +0100382 break;
383 }
384
385 case DRM_IOCTL_PRIME_FD_TO_HANDLE: {
386 struct drm_prime_handle *prime = argp;
387 off_t size = lseek(prime->fd, 0, SEEK_END);
388 fail_if(size == -1, "failed to get prime bo size\n");
Chris Wilson49e09e72017-03-28 11:26:39 +0100389 trace_add(t, prime->handle, size);
Chris Wilsona64e6c32015-08-14 20:31:48 +0100390 break;
391 }
392
393 case DRM_IOCTL_MODE_GETFB: {
394 struct drm_mode_fb_cmd *cmd = argp;
Chris Wilson49e09e72017-03-28 11:26:39 +0100395 trace_add(t, cmd->handle, size_for_fb(cmd));
396 break;
397 }
398
399 case DRM_IOCTL_I915_GEM_CONTEXT_CREATE: {
400 struct drm_i915_gem_context_create *create = argp;
401 trace_add_context(t, create->ctx_id);
Chris Wilsona64e6c32015-08-14 20:31:48 +0100402 break;
403 }
404 }
405
406 return 0;
Chris Wilson49e09e72017-03-28 11:26:39 +0100407
408untraced:
409 return libc_ioctl(fd, request, argp);
Chris Wilson0393e722015-08-09 17:39:41 +0100410}
411
412static void __attribute__ ((constructor))
413init(void)
414{
415 libc_close = dlsym(RTLD_NEXT, "close");
416 libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
417 fail_if(libc_close == NULL || libc_ioctl == NULL,
418 "failed to get libc ioctl or close\n");
419}