blob: fb5c0f30dad515ce7dc5e16c4783e265c549dbee [file] [log] [blame]
Chris Wilson529c0d12017-04-26 18:19:46 +01001/*
2 * Copyright © 2017 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
25#include "igt.h"
26#include "igt_rand.h"
27#include "igt_sysfs.h"
28#include "igt_vgem.h"
29
30#include <sys/ioctl.h>
31#include <sys/signal.h>
32
33#define LOCAL_I915_EXEC_NO_RELOC (1<<11)
34#define LOCAL_I915_EXEC_HANDLE_LUT (1<<12)
35
36#define LOCAL_I915_EXEC_BSD_SHIFT (13)
37#define LOCAL_I915_EXEC_BSD_MASK (3 << LOCAL_I915_EXEC_BSD_SHIFT)
38
39#define ENGINE_FLAGS (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
40
41static double elapsed(const struct timespec *start, const struct timespec *end)
42{
43 return ((end->tv_sec - start->tv_sec) +
44 (end->tv_nsec - start->tv_nsec)*1e-9);
45}
46
47static bool ignore_engine(int fd, unsigned engine)
48{
49 if (engine == 0)
50 return true;
51
52 if (gem_has_bsd2(fd) && engine == I915_EXEC_BSD)
53 return true;
54
55 return false;
56}
57
58static uint32_t __gem_context_create(int fd)
59{
60 struct drm_i915_gem_context_create arg;
61
62 memset(&arg, 0, sizeof(arg));
63 drmIoctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &arg);
64 return arg.ctx_id;
65}
66
67static void xchg_obj(void *array, unsigned i, unsigned j)
68{
69 struct drm_i915_gem_exec_object2 *obj = array;
70 uint64_t tmp;
71
72 tmp = obj[i].handle;
73 obj[i].handle = obj[j].handle;
74 obj[j].handle = tmp;
75
76 tmp = obj[i].offset;
77 obj[i].offset = obj[j].offset;
78 obj[j].offset = tmp;
79}
80
81#define CONTEXTS 0x1
82static void wide(int fd, int ring_size, int timeout, unsigned int flags)
83{
84 const uint32_t bbe = MI_BATCH_BUFFER_END;
85 const int gen = intel_gen(intel_get_drm_devid(fd));
86 struct {
87 struct drm_i915_gem_exec_object2 *obj;
88 struct drm_i915_gem_exec_object2 exec[2];
89 struct drm_i915_gem_relocation_entry reloc;
90 struct drm_i915_gem_execbuffer2 execbuf;
91 uint32_t *cmd;
92 } *exec;
93 struct drm_i915_gem_exec_object2 *obj;
94 struct drm_i915_gem_execbuffer2 execbuf;
95 unsigned engines[16];
96 unsigned nengine, engine;
97 unsigned long count;
98 double time;
99
100 nengine = 0;
101 for_each_engine(fd, engine) {
102 if (ignore_engine(fd, engine))
103 continue;
104
105 engines[nengine++] = engine;
106 }
107 igt_require(nengine);
108
109 exec = calloc(nengine, sizeof(*exec));
110 igt_assert(exec);
111
112 intel_require_memory(nengine*(2 + ring_size), 4096, CHECK_RAM);
113 obj = calloc(nengine*ring_size + 1, sizeof(*obj));
114 igt_assert(obj);
115
116 for (unsigned e = 0; e < nengine; e++) {
117 exec[e].obj = calloc(ring_size, sizeof(*exec[e].obj));
118 igt_assert(exec[e].obj);
119 for (unsigned n = 0; n < ring_size; n++) {
120 exec[e].obj[n].handle = gem_create(fd, 4096);
121 exec[e].obj[n].flags = EXEC_OBJECT_WRITE;
122
123 obj[e*ring_size + n].handle = exec[e].obj[n].handle;
124 }
125
126 exec[e].execbuf.buffers_ptr = to_user_pointer(exec[e].exec);
127 exec[e].execbuf.buffer_count = 1;
128 exec[e].execbuf.flags = (engines[e] |
129 LOCAL_I915_EXEC_NO_RELOC |
130 LOCAL_I915_EXEC_HANDLE_LUT);
131
132 if (flags & CONTEXTS) {
133 exec[e].execbuf.rsvd1 = __gem_context_create(fd);
134 igt_require(exec[e].execbuf.rsvd1);
135 }
136
137 exec[e].exec[0].handle = gem_create(fd, 4096);
138 exec[e].cmd = gem_mmap__wc(fd, exec[e].exec[0].handle,
139 0, 4096, PROT_WRITE);
140
141 gem_set_domain(fd, exec[e].exec[0].handle,
142 I915_GEM_DOMAIN_WC, I915_GEM_DOMAIN_WC);
143 exec[e].cmd[0] = MI_BATCH_BUFFER_END;
144
145 gem_execbuf(fd, &exec[e].execbuf);
146 exec[e].exec[1] = exec[e].exec[0];
147 exec[e].execbuf.buffer_count = 2;
148
149 exec[e].reloc.target_handle = 1; /* recurse */
150 exec[e].reloc.offset = sizeof(uint32_t);
151 exec[e].reloc.read_domains = I915_GEM_DOMAIN_COMMAND;
152 if (gen < 4)
153 exec[e].reloc.delta = 1;
154
155 exec[e].exec[1].relocs_ptr = to_user_pointer(&exec[e].reloc);
156 exec[e].exec[1].relocation_count = 1;
157 }
158 obj[nengine*ring_size].handle = gem_create(fd, 4096);
159 gem_write(fd, obj[nengine*ring_size].handle, 0, &bbe, sizeof(bbe));
160
161 memset(&execbuf, 0, sizeof(execbuf));
162 execbuf.buffers_ptr = to_user_pointer(obj);
163 execbuf.buffer_count = nengine*ring_size + 1;
164
165 intel_detect_and_clear_missed_interrupts(fd);
166
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100167 time = 0;
Chris Wilson529c0d12017-04-26 18:19:46 +0100168 count = 0;
169 igt_until_timeout(timeout) {
170 struct timespec start, now;
171 for (unsigned e = 0; e < nengine; e++) {
172 uint64_t address;
173 int i;
174
175 if (flags & CONTEXTS) {
176 gem_context_destroy(fd, exec[e].execbuf.rsvd1);
177 exec[e].execbuf.rsvd1 = __gem_context_create(fd);
178 }
179
180 exec[e].reloc.presumed_offset = exec[e].exec[1].offset;
181 address = (exec[e].reloc.presumed_offset +
182 exec[e].reloc.delta);
183 gem_set_domain(fd, exec[e].exec[1].handle,
184 I915_GEM_DOMAIN_WC, I915_GEM_DOMAIN_WC);
185
186 i = 0;
187 exec[e].cmd[i] = MI_BATCH_BUFFER_START;
188 if (gen >= 8) {
189 exec[e].cmd[i] |= 1 << 8 | 1;
190 exec[e].cmd[++i] = address;
191 exec[e].cmd[++i] = address >> 32;
192 } else if (gen >= 6) {
193 exec[e].cmd[i] |= 1 << 8;
194 exec[e].cmd[++i] = address;
195 } else {
196 exec[e].cmd[i] |= 2 << 6;
197 exec[e].cmd[++i] = address;
198 }
199
200 exec[e].exec[0] = obj[nengine*ring_size];
201 gem_execbuf(fd, &exec[e].execbuf);
202
203 for (unsigned n = 0; n < ring_size; n++) {
204 exec[e].exec[0] = exec[e].obj[n];
205 gem_execbuf(fd, &exec[e].execbuf);
206 exec[e].obj[n].offset = exec[e].exec[0].offset;
207 }
208 }
209
210 igt_permute_array(obj, nengine*ring_size, xchg_obj);
211
212 clock_gettime(CLOCK_MONOTONIC, &start);
213 for (unsigned e = 0; e < nengine; e++) {
214 execbuf.flags = (engines[e] |
215 LOCAL_I915_EXEC_NO_RELOC |
216 LOCAL_I915_EXEC_HANDLE_LUT);
217 gem_execbuf(fd, &execbuf);
218 }
219 clock_gettime(CLOCK_MONOTONIC, &now);
220 time += elapsed(&start, &now);
221 count += nengine;
222
223 for (unsigned e = 0; e < nengine; e++)
224 exec[e].cmd[0] = MI_BATCH_BUFFER_END;
225 }
226
227 igt_assert_eq(intel_detect_and_clear_missed_interrupts(fd), 0);
228
229 igt_info("%s: %'lu cycles: %.3fus\n",
230 __func__, count, time*1e6 / count);
231
232 gem_close(fd, obj[nengine*ring_size].handle);
233 free(obj);
234
235 for (unsigned e = 0; e < nengine; e++) {
236 if (flags & CONTEXTS)
237 gem_context_destroy(fd, exec[e].execbuf.rsvd1);
238
239 for (unsigned n = 0; n < ring_size; n++)
240 gem_close(fd, exec[e].obj[n].handle);
241 free(exec[e].obj);
242
243 munmap(exec[e].cmd, 4096);
244 gem_close(fd, exec[e].exec[1].handle);
245 }
246 free(exec);
247}
248
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100249#define HAVE_EXECLISTS 0x1
250static unsigned int print_welcome(int fd)
Chris Wilson529c0d12017-04-26 18:19:46 +0100251{
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100252 unsigned int result = 0;
Chris Wilson529c0d12017-04-26 18:19:46 +0100253 bool active;
254 int dir;
255
256 dir = igt_sysfs_open_parameters(fd);
257 if (dir < 0)
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100258 return 0;
Chris Wilson529c0d12017-04-26 18:19:46 +0100259
260 active = igt_sysfs_get_boolean(dir, "enable_guc_submission");
261 if (active) {
262 igt_info("Using GuC submission\n");
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100263 result |= HAVE_EXECLISTS;
Chris Wilson529c0d12017-04-26 18:19:46 +0100264 goto out;
265 }
266
267 active = igt_sysfs_get_boolean(dir, "enable_execlists");
268 if (active) {
269 igt_info("Using Execlists submission\n");
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100270 result |= HAVE_EXECLISTS;
Chris Wilson529c0d12017-04-26 18:19:46 +0100271 goto out;
272 }
273
274 active = igt_sysfs_get_boolean(dir, "semaphores");
275 igt_info("Using Legacy submission%s\n",
276 active ? ", with semaphores" : "");
277
278out:
279 close(dir);
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100280 return result;
Chris Wilson529c0d12017-04-26 18:19:46 +0100281}
282
283struct cork {
284 int device;
285 uint32_t handle;
286 uint32_t fence;
287};
288
289static void plug(int fd, struct cork *c)
290{
291 struct vgem_bo bo;
292 int dmabuf;
293
294 c->device = drm_open_driver(DRIVER_VGEM);
295
296 bo.width = bo.height = 1;
297 bo.bpp = 4;
298 vgem_create(c->device, &bo);
299 c->fence = vgem_fence_attach(c->device, &bo, VGEM_FENCE_WRITE);
300
301 dmabuf = prime_handle_to_fd(c->device, bo.handle);
302 c->handle = prime_fd_to_handle(fd, dmabuf);
303 close(dmabuf);
304}
305
306static void unplug(struct cork *c)
307{
308 vgem_fence_signal(c->device, c->fence);
309 close(c->device);
310}
311
312static void alarm_handler(int sig)
313{
314}
315
316static int __execbuf(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
317{
318 return ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
319}
320
321static unsigned int measure_ring_size(int fd)
322{
323 struct sigaction sa = { .sa_handler = alarm_handler };
324 struct drm_i915_gem_exec_object2 obj[2];
325 struct drm_i915_gem_execbuffer2 execbuf;
326 const uint32_t bbe = MI_BATCH_BUFFER_END;
327 unsigned int count, last;
328 struct itimerval itv;
329 struct cork c;
330
331 memset(obj, 0, sizeof(obj));
332 obj[1].handle = gem_create(fd, 4096);
333 gem_write(fd, obj[1].handle, 0, &bbe, sizeof(bbe));
334
335 plug(fd, &c);
336 obj[0].handle = c.handle;
337
338 memset(&execbuf, 0, sizeof(execbuf));
339 execbuf.buffers_ptr = to_user_pointer(obj);
340 execbuf.buffer_count = 2;
341
342 sigaction(SIGALRM, &sa, NULL);
343 itv.it_interval.tv_sec = 0;
344 itv.it_interval.tv_usec = 100;
345 itv.it_value.tv_sec = 0;
346 itv.it_value.tv_usec = 1000;
347 setitimer(ITIMER_REAL, &itv, NULL);
348
349 last = count = 0;
350 do {
351 if (__execbuf(fd, &execbuf) == 0) {
352 count++;
353 continue;
354 }
355
356 if (last == count)
357 break;
358
359 last = count;
360 } while (1);
361
362 memset(&itv, 0, sizeof(itv));
363 setitimer(ITIMER_REAL, &itv, NULL);
364
365 unplug(&c);
366 gem_close(fd, obj[1].handle);
367
368 return count;
369}
370
371igt_main
372{
373 int ring_size = 0;
374 int device = -1;
375
376 igt_fixture {
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100377 unsigned int caps;
378
Chris Wilson529c0d12017-04-26 18:19:46 +0100379 device = drm_open_driver(DRIVER_INTEL);
380 igt_require_gem(device);
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100381 caps = print_welcome(device);
Chris Wilson529c0d12017-04-26 18:19:46 +0100382
383 ring_size = measure_ring_size(device) - 10;
Chris Wilsond0e1eb92017-06-09 15:15:45 +0100384 if (!(caps & HAVE_EXECLISTS))
385 ring_size /= 2;
Chris Wilson529c0d12017-04-26 18:19:46 +0100386 igt_info("Ring size: %d batches\n", ring_size);
387 igt_require(ring_size > 0);
388
389 igt_fork_hang_detector(device);
390 }
391
392 igt_subtest("wide-all")
393 wide(device, ring_size, 20, 0);
394
395 igt_subtest("wide-contexts")
396 wide(device, ring_size, 20, CONTEXTS);
397
398 igt_fixture {
399 igt_stop_hang_detector();
400 close(device);
401 }
402}