blob: ccc2d23a6425b8d738d6ff3dde87693082d63f8a [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
24#define _GNU_SOURCE /* for RTLD_NEXT */
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <stdint.h>
30#include <stdbool.h>
31#include <stdarg.h>
32#include <fcntl.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/ioctl.h>
36#include <unistd.h>
37#include <errno.h>
38#include <sys/mman.h>
39#include <dlfcn.h>
40#include <i915_drm.h>
41
42#include "intel_aub.h"
43#include "intel_chipset.h"
44
45static int (*libc_close)(int fd);
46static int (*libc_ioctl)(int fd, unsigned long request, void *argp);
47
48static int drm_fd = -1;
49static FILE *file;
50
51#define DRM_MAJOR 226
52
53enum {
54 ADD_BO = 0,
55 DEL_BO,
56 EXEC,
57};
58
59struct trace_add_bo {
60 uint8_t cmd;
61 uint32_t handle;
62 uint64_t size;
63} __attribute__((packed));
64struct trace_del_bo {
65 uint8_t cmd;
66 uint32_t handle;
67}__attribute__((packed));
68
69struct trace_exec {
70 uint8_t cmd;
71 uint32_t object_count;
72 uint64_t flags;
73}__attribute__((packed));
74
75struct trace_exec_object {
76 uint32_t handle;
77 uint32_t relocation_count;
78 uint64_t alignment;
79 uint64_t flags;
80 uint64_t rsvd1;
81 uint64_t rsvd2;
82}__attribute__((packed));
83
84struct trace_exec_relocation {
85 uint32_t target_handle;
86 uint32_t delta;
87 uint64_t offset;
88 uint32_t read_domains;
89 uint32_t write_domain;
90}__attribute__((packed));
91
92static void __attribute__ ((format(__printf__, 2, 3)))
93fail_if(int cond, const char *format, ...)
94{
95 va_list args;
96
97 if (!cond)
98 return;
99
100 va_start(args, format);
101 vfprintf(stderr, format, args);
102 va_end(args);
103
104 exit(1);
105}
106
107static void
108trace_exec(int fd, const struct drm_i915_gem_execbuffer2 *execbuffer2)
109{
110 const struct drm_i915_gem_exec_object2 *exec_objects =
111 (struct drm_i915_gem_exec_object2 *)(uintptr_t)execbuffer2->buffers_ptr;
112
113 {
114 struct trace_exec t = {
Chris Wilson39116212015-08-10 18:17:47 +0100115 EXEC, execbuffer2->buffer_count, execbuffer2->flags
116 };
Chris Wilson0393e722015-08-09 17:39:41 +0100117 fwrite(&t, sizeof(t), 1, file);
118 }
119
120 for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) {
121 const struct drm_i915_gem_exec_object2 *obj = &exec_objects[i];
122 const struct drm_i915_gem_relocation_entry *relocs =
123 (struct drm_i915_gem_relocation_entry *)(uintptr_t)obj->relocs_ptr;
124 {
125 struct trace_exec_object t = {
126 obj->handle,
127 obj->relocation_count,
128 obj->alignment,
129 obj->flags,
130 obj->rsvd1,
131 obj->rsvd2
132 };
133 fwrite(&t, sizeof(t), 1, file);
134 }
135 for (uint32_t j = 0; j < obj->relocation_count; j++) {
136 struct trace_exec_relocation t = {
137 relocs[j].target_handle,
138 relocs[j].delta,
139 relocs[j].offset,
140 relocs[j].read_domains,
141 relocs[j].write_domain,
142 };
143 fwrite(&t, sizeof(t), 1, file);
144 }
145 }
146
147 fflush(file);
148}
149
150static void
151trace_add(uint32_t handle, uint64_t size)
152{
153 struct trace_add_bo t = { ADD_BO, handle, size };
154 fwrite(&t, sizeof(t), 1, file);
155}
156
157static void
158trace_del(uint32_t handle)
159{
160 struct trace_del_bo t = { DEL_BO, handle };
161 fwrite(&t, sizeof(t), 1, file);
162}
163
164int
165close(int fd)
166{
167 if (fd == drm_fd)
168 drm_fd = -1;
169
170 return libc_close(fd);
171}
172
173int
174ioctl(int fd, unsigned long request, ...)
175{
176 va_list args;
177 void *argp;
178 int ret;
179
180 va_start(args, request);
181 argp = va_arg(args, void *);
182 va_end(args);
183
184 if (_IOC_TYPE(request) == DRM_IOCTL_BASE && drm_fd != fd) {
185 char filename[80];
186 if (file)
187 fclose(file);
188 sprintf(filename, "/tmp/trace.%d", fd);
189 file = fopen(filename, "w+");
190 drm_fd = fd;
191 }
192
193 if (fd == drm_fd) {
194 switch (request) {
195 case DRM_IOCTL_I915_GEM_EXECBUFFER: {
196 return libc_ioctl(fd, request, argp);
197 }
198
199 case DRM_IOCTL_I915_GEM_EXECBUFFER2: {
200 trace_exec(fd, argp);
201 return libc_ioctl(fd, request, argp);
202 }
203
204 case DRM_IOCTL_I915_GEM_CREATE: {
205 struct drm_i915_gem_create *create = argp;
206
207 ret = libc_ioctl(fd, request, argp);
208 if (ret == 0)
209 trace_add(create->handle, create->size);
210
211 return ret;
212 }
213
214 case DRM_IOCTL_I915_GEM_USERPTR: {
215 struct drm_i915_gem_userptr *userptr = argp;
216
217 ret = libc_ioctl(fd, request, argp);
218 if (ret == 0)
219 trace_add(userptr->handle, userptr->user_size);
220 return ret;
221 }
222
223 case DRM_IOCTL_GEM_CLOSE: {
224 struct drm_gem_close *close = argp;
225
226 trace_del(close->handle);
227
228 return libc_ioctl(fd, request, argp);
229 }
230
231 case DRM_IOCTL_GEM_OPEN: {
232 struct drm_gem_open *open = argp;
233
234 ret = libc_ioctl(fd, request, argp);
235 if (ret == 0)
236 trace_add(open->handle, open->size);
237
238 return ret;
239 }
240
241 case DRM_IOCTL_PRIME_FD_TO_HANDLE: {
242 struct drm_prime_handle *prime = argp;
243
244 ret = libc_ioctl(fd, request, argp);
245 if (ret == 0) {
246 off_t size;
247
248 size = lseek(prime->fd, 0, SEEK_END);
249 fail_if(size == -1, "failed to get prime bo size\n");
250 trace_add(prime->handle, size);
251 }
252
253 return ret;
254 }
255
256 default:
257 return libc_ioctl(fd, request, argp);
258 }
259 } else {
260 return libc_ioctl(fd, request, argp);
261 }
262}
263
264static void __attribute__ ((constructor))
265init(void)
266{
267 libc_close = dlsym(RTLD_NEXT, "close");
268 libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
269 fail_if(libc_close == NULL || libc_ioctl == NULL,
270 "failed to get libc ioctl or close\n");
271}