blob: f7716dfa57484cf268a38cb5fe51196b7609ff12 [file] [log] [blame]
Tvrtko Ursulind3057d72014-04-25 15:42:20 +01001/*
2 * Copyright © 2014 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 * Authors:
24 * Tvrtko Ursulin <tvrtko.ursulin@intel.com>
25 *
26 */
27
28/** @file gem_userptr_benchmark.c
29 *
30 * Benchmark the userptr code and impact of having userptr surfaces
31 * in process address space on some normal operations.
32 *
33 */
34
35#include <stdlib.h>
36#include <stdio.h>
37#include <string.h>
38#include <fcntl.h>
39#include <inttypes.h>
40#include <errno.h>
41#include <assert.h>
42#include <sys/stat.h>
43#include <sys/time.h>
44#include <sys/mman.h>
Daniel Vetter1b558862014-04-25 17:52:02 +020045#include <signal.h>
46
Tvrtko Ursulind3057d72014-04-25 15:42:20 +010047#include "drm.h"
48#include "i915_drm.h"
Daniel Vetter1b558862014-04-25 17:52:02 +020049
Tvrtko Ursulind3057d72014-04-25 15:42:20 +010050#include "drmtest.h"
51#include "intel_bufmgr.h"
52#include "intel_batchbuffer.h"
53#include "intel_chipset.h"
54#include "ioctl_wrappers.h"
55#include "igt_aux.h"
56
57#ifndef PAGE_SIZE
58 #define PAGE_SIZE 4096
59#endif
60
Tvrtko Ursulind3057d72014-04-25 15:42:20 +010061static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
62
63#define BO_SIZE (65536)
64
65static void gem_userptr_test_unsynchronized(void)
66{
67 userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
68}
69
70static void gem_userptr_test_synchronized(void)
71{
72 userptr_flags = 0;
73}
74
Tvrtko Ursulind3057d72014-04-25 15:42:20 +010075static void **handle_ptr_map;
76static unsigned int num_handle_ptr_map;
77
78static void add_handle_ptr(uint32_t handle, void *ptr)
79{
80 if (handle >= num_handle_ptr_map) {
81 handle_ptr_map = realloc(handle_ptr_map,
82 (handle + 1000) * sizeof(void*));
83 num_handle_ptr_map = handle + 1000;
84 }
85
86 handle_ptr_map[handle] = ptr;
87}
88
89static void *get_handle_ptr(uint32_t handle)
90{
91 return handle_ptr_map[handle];
92}
93
94static void free_handle_ptr(uint32_t handle)
95{
96 igt_assert(handle < num_handle_ptr_map);
97 igt_assert(handle_ptr_map[handle]);
98
99 free(handle_ptr_map[handle]);
100 handle_ptr_map[handle] = NULL;
101}
102
103static uint32_t create_userptr_bo(int fd, int size)
104{
105 void *ptr;
106 uint32_t handle;
107 int ret;
108
109 ret = posix_memalign(&ptr, PAGE_SIZE, size);
110 igt_assert(ret == 0);
111
Tiago Vignattie1f663b2015-08-12 15:57:12 -0300112 gem_userptr(fd, (uint32_t *)ptr, size, 0, userptr_flags, &handle);
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100113 add_handle_ptr(handle, ptr);
114
115 return handle;
116}
117
118static void free_userptr_bo(int fd, uint32_t handle)
119{
120 gem_close(fd, handle);
121 free_handle_ptr(handle);
122}
123
124static int has_userptr(int fd)
125{
126 uint32_t handle = 0;
127 void *ptr;
128 uint32_t oldflags;
129 int ret;
130
131 assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
132 oldflags = userptr_flags;
133 gem_userptr_test_unsynchronized();
Tiago Vignattie1f663b2015-08-12 15:57:12 -0300134 ret = __gem_userptr(fd, ptr, PAGE_SIZE, 0, userptr_flags, &handle);
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100135 userptr_flags = oldflags;
136 if (ret != 0) {
137 free(ptr);
138 return 0;
139 }
140
141 gem_close(fd, handle);
142 free(ptr);
143
144 return handle != 0;
145}
146
Tvrtko Ursulin85ee6e72015-06-01 11:11:15 +0100147static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000, 10000};
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100148static const unsigned int test_duration_sec = 3;
149
150static volatile unsigned int run_test;
151
152static void alarm_handler(int sig)
153{
154 assert(run_test == 1);
155 run_test = 0;
156}
157
158static void start_test(unsigned int duration)
159{
160 run_test = 1;
161 if (duration == 0)
162 duration = test_duration_sec;
163 signal(SIGALRM, alarm_handler);
164 alarm(duration);
165}
166
167static void exchange_ptr(void *array, unsigned i, unsigned j)
168{
169 void **arr, *tmp;
170 arr = (void **)array;
171
172 tmp = arr[i];
173 arr[i] = arr[j];
174 arr[j] = tmp;
175}
176
177static void test_malloc_free(int random)
178{
179 unsigned long iter = 0;
180 unsigned int i, tot = 1000;
181 void *ptr[tot];
182
183 start_test(test_duration_sec);
184
185 while (run_test) {
186 for (i = 0; i < tot; i++) {
187 ptr[i] = malloc(1000);
188 assert(ptr[i]);
189 }
190 if (random)
191 igt_permute_array(ptr, tot, exchange_ptr);
192 for (i = 0; i < tot; i++)
193 free(ptr[i]);
194 iter++;
195 }
196
197 printf("%8lu iter/s\n", iter / test_duration_sec);
198}
199
200static void test_malloc_realloc_free(int random)
201{
202 unsigned long iter = 0;
203 unsigned int i, tot = 1000;
204 void *ptr[tot];
205
206 start_test(test_duration_sec);
207
208 while (run_test) {
209 for (i = 0; i < tot; i++) {
210 ptr[i] = malloc(1000);
211 assert(ptr[i]);
212 }
213 if (random)
214 igt_permute_array(ptr, tot, exchange_ptr);
215 for (i = 0; i < tot; i++) {
216 ptr[i] = realloc(ptr[i], 2000);
217 assert(ptr[i]);
218 }
219 if (random)
220 igt_permute_array(ptr, tot, exchange_ptr);
221 for (i = 0; i < tot; i++)
222 free(ptr[i]);
223 iter++;
224 }
225
226 printf("%8lu iter/s\n", iter / test_duration_sec);
227}
228
229static void test_mmap_unmap(int random)
230{
231 unsigned long iter = 0;
232 unsigned int i, tot = 1000;
233 void *ptr[tot];
234
235 start_test(test_duration_sec);
236
237 while (run_test) {
238 for (i = 0; i < tot; i++) {
239 ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
240 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
241 assert(ptr[i] != MAP_FAILED);
242 }
243 if (random)
244 igt_permute_array(ptr, tot, exchange_ptr);
245 for (i = 0; i < tot; i++)
246 munmap(ptr[i], 1000);
247 iter++;
248 }
249
250 printf("%8lu iter/s\n", iter / test_duration_sec);
251}
252
253static void test_ptr_read(void *ptr)
254{
255 unsigned long iter = 0;
256 volatile unsigned long *p;
257 unsigned long i, loops;
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100258
259 loops = BO_SIZE / sizeof(unsigned long) / 4;
260
261 start_test(test_duration_sec);
262
263 while (run_test) {
264 p = (unsigned long *)ptr;
265 for (i = 0; i < loops; i++) {
Daniel Vetter1b558862014-04-25 17:52:02 +0200266 (void)*p++;
267 (void)*p++;
268 (void)*p++;
269 (void)*p++;
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100270 }
271 iter++;
272 }
273
274 printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
275}
276
277static void test_ptr_write(void *ptr)
278{
279 unsigned long iter = 0;
280 volatile unsigned long *p;
281 register unsigned long i, loops;
282
283 loops = BO_SIZE / sizeof(unsigned long) / 4;
284
285 start_test(test_duration_sec);
286
287 while (run_test) {
288 p = (unsigned long *)ptr;
289 for (i = 0; i < loops; i++) {
290 *p++ = i;
291 *p++ = i;
292 *p++ = i;
293 *p++ = i;
294 }
295 iter++;
296 }
297
298 printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
299}
300
Tvrtko Ursulin85ee6e72015-06-01 11:11:15 +0100301static void do_impact_tests(unsigned int n, const char *pfix, const char *pfix2,
302 void *ptr)
303{
304 printf("%s%sptr-read, %5u bos = ", pfix, pfix2, n);
305 test_ptr_read(ptr);
306
307 printf("%s%sptr-write %5u bos = ", pfix, pfix2, n);
308 test_ptr_write(ptr);
309
310 printf("%s%smalloc-free, %5u bos = ", pfix, pfix2, n);
311 test_malloc_free(0);
312 printf("%s%smalloc-free-random %5u bos = ", pfix, pfix2, n);
313 test_malloc_free(1);
314
315 printf("%s%smalloc-realloc-free, %5u bos = ", pfix, pfix2, n);
316 test_malloc_realloc_free(0);
317 printf("%s%smalloc-realloc-free-random, %5u bos = ", pfix, pfix2, n);
318 test_malloc_realloc_free(1);
319
320 printf("%s%smmap-unmap, %5u bos = ", pfix, pfix2, n);
321 test_mmap_unmap(0);
322 printf("%s%smmap-unmap-random, %5u bos = ", pfix, pfix2, n);
323 test_mmap_unmap(1);
324}
325
326static void test_impact_overlap(int fd, const char *prefix)
327{
328 unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
329 unsigned int subtest, i;
330 uint32_t handles[nr_bos[total-1]];
331 void *block = NULL;
332 void *ptr;
333 unsigned char *p;
334 char buffer[BO_SIZE];
335 int ret;
336
337 for (subtest = 0; subtest < total; subtest++) {
338 if (nr_bos[subtest] > 0) {
339 igt_assert(PAGE_SIZE < BO_SIZE);
340 ret = posix_memalign(&block, PAGE_SIZE,
341 PAGE_SIZE * nr_bos[subtest] + BO_SIZE);
342 igt_assert(ret == 0);
343
344 for (i = 0, p = block; i < nr_bos[subtest];
345 i++, p += PAGE_SIZE)
Tiago Vignattie1f663b2015-08-12 15:57:12 -0300346 gem_userptr(fd, (uint32_t *)p, BO_SIZE, 0, userptr_flags, &handles[i]);
Tvrtko Ursulin85ee6e72015-06-01 11:11:15 +0100347 }
348
349 if (nr_bos[subtest] > 0)
350 ptr = block;
351 else
352 ptr = buffer;
353
354 do_impact_tests(nr_bos[subtest], prefix, "overlap-", ptr);
355
356 for (i = 0; i < nr_bos[subtest]; i++)
357 gem_close(fd, handles[i]);
358 if (block)
359 free(block);
360 }
361}
362
363static void test_impact(int fd, const char *prefix)
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100364{
365 unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
366 unsigned int subtest, i;
367 uint32_t handles[nr_bos[total-1]];
368 void *ptr;
369 char buffer[BO_SIZE];
370
371 for (subtest = 0; subtest < total; subtest++) {
372 for (i = 0; i < nr_bos[subtest]; i++)
373 handles[i] = create_userptr_bo(fd, BO_SIZE);
374
375 if (nr_bos[subtest] > 0)
376 ptr = get_handle_ptr(handles[0]);
377 else
378 ptr = buffer;
379
Tvrtko Ursulin85ee6e72015-06-01 11:11:15 +0100380 do_impact_tests(nr_bos[subtest], prefix, "no-overlap-", ptr);
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100381
382 for (i = 0; i < nr_bos[subtest]; i++)
383 free_userptr_bo(fd, handles[i]);
384 }
385}
386
387static void test_single(int fd)
388{
389 char *ptr, *bo_ptr;
390 uint32_t handle = 0;
391 unsigned long iter = 0;
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100392 unsigned long map_size = BO_SIZE + PAGE_SIZE - 1;
393
394 ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
395 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
396 assert(ptr != MAP_FAILED);
397
398 bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
399
400 start_test(test_duration_sec);
401
402 while (run_test) {
Tiago Vignattie1f663b2015-08-12 15:57:12 -0300403 gem_userptr(fd, bo_ptr, BO_SIZE, 0, userptr_flags, &handle);
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100404 gem_close(fd, handle);
405 iter++;
406 }
407
408 munmap(ptr, map_size);
409
410 printf("%8lu iter/s\n", iter / test_duration_sec);
411}
412
413static void test_multiple(int fd, unsigned int batch, int random)
414{
415 char *ptr, *bo_ptr;
416 uint32_t handles[10000];
417 int map[10000];
418 unsigned long iter = 0;
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100419 int i;
420 unsigned long map_size = batch * BO_SIZE + PAGE_SIZE - 1;
421
422 assert(batch < (sizeof(handles) / sizeof(handles[0])));
423 assert(batch < (sizeof(map) / sizeof(map[0])));
424
425 ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
426 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
427 assert(ptr != MAP_FAILED);
428
429 bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
430
431 for (i = 0; i < batch; i++)
432 map[i] = i;
433
434 start_test(test_duration_sec);
435
436 while (run_test) {
437 if (random)
438 igt_permute_array(map, batch, igt_exchange_int);
439 for (i = 0; i < batch; i++) {
Tiago Vignattie1f663b2015-08-12 15:57:12 -0300440 gem_userptr(fd, bo_ptr + map[i] * BO_SIZE, BO_SIZE,
441 0, userptr_flags, &handles[i]);
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100442 }
443 if (random)
444 igt_permute_array(map, batch, igt_exchange_int);
445 for (i = 0; i < batch; i++)
446 gem_close(fd, handles[map[i]]);
447 iter++;
448 }
449
450 munmap(ptr, map_size);
451
452 printf("%8lu iter/s\n", iter * batch / test_duration_sec);
453}
454
455static void test_userptr(int fd)
456{
457 printf("create-destroy = ");
458 test_single(fd);
459
460 printf("multi-create-destroy = ");
461 test_multiple(fd, 100, 0);
462
463 printf("multi-create-destroy-random = ");
464 test_multiple(fd, 100, 1);
465}
466
467int main(int argc, char **argv)
468{
469 int fd = -1, ret;
470
471 igt_skip_on_simulation();
472
473 igt_subtest_init(argc, argv);
474
Micah Fedkec81d2932015-07-22 21:54:02 +0000475 fd = drm_open_driver(DRIVER_INTEL);
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100476 igt_assert(fd >= 0);
477
478 ret = has_userptr(fd);
479 igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
480 strerror(errno), ret);
481
482
483 gem_userptr_test_unsynchronized();
484
485 igt_subtest("userptr-unsync")
486 test_userptr(fd);
487
488 igt_subtest("userptr-impact-unsync")
Tvrtko Ursulin85ee6e72015-06-01 11:11:15 +0100489 test_impact(fd, "unsync-");
490
491 igt_subtest("userptr-impact-unsync-overlap")
492 test_impact_overlap(fd, "unsync-");
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100493
494 gem_userptr_test_synchronized();
495
496 igt_subtest("userptr-sync")
497 test_userptr(fd);
498
499 igt_subtest("userptr-impact-sync")
Tvrtko Ursulin85ee6e72015-06-01 11:11:15 +0100500 test_impact(fd, "sync-");
501
502 igt_subtest("userptr-impact-sync-overlap")
503 test_impact_overlap(fd, "sync-");
Tvrtko Ursulind3057d72014-04-25 15:42:20 +0100504
505 igt_exit();
506
507 return 0;
508}