All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] tests: New userptr test case
@ 2014-02-26 16:17 Tvrtko Ursulin
  2014-02-26 16:17 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
                   ` (5 more replies)
  0 siblings, 6 replies; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-02-26 16:17 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This patch series replaces the old vmap with the new userptr test case
and also adds a benchmark for the new feature.

Tested against version 20 of the kernel patch.

Tvrtko Ursulin (3):
  tests/gem_userptr_blits: Expanded userptr test cases
  tests/gem_vmap_blits: Remove obsolete test case
  tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact

 Android.mk                         |    3 +-
 benchmarks/.gitignore              |    1 +
 benchmarks/Android.mk              |   36 ++
 benchmarks/Makefile.am             |    7 +-
 benchmarks/Makefile.sources        |    6 +
 benchmarks/gem_userptr_benchmark.c |  513 +++++++++++++++
 tests/.gitignore                   |    2 +-
 tests/Makefile.sources             |    2 +-
 tests/gem_userptr_blits.c          | 1230 ++++++++++++++++++++++++++++++++++++
 tests/gem_vmap_blits.c             |  344 ----------
 10 files changed, 1790 insertions(+), 354 deletions(-)
 create mode 100644 benchmarks/Android.mk
 create mode 100644 benchmarks/Makefile.sources
 create mode 100644 benchmarks/gem_userptr_benchmark.c
 create mode 100644 tests/gem_userptr_blits.c
 delete mode 100644 tests/gem_vmap_blits.c

-- 
1.9.0

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-02-26 16:17 [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
@ 2014-02-26 16:17 ` Tvrtko Ursulin
  2014-03-05 14:48   ` Chris Wilson
  2014-02-26 16:17 ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-02-26 16:17 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

A set of userptr test cases to support the new feature.

For the eviction and swapping stress testing I have extracted
some common behaviour from gem_evict_everything and made both
test cases use it to avoid duplicating the code.

Both unsynchronized and synchronized userptr objects are
tested but the latter set of tests will be skipped if kernel
is compiled without MMU_NOTIFIERS.

Also, with 32-bit userspace swapping tests are skipped if
the system has a lot more RAM than process address space.
Forking swapping tests are not skipped since they can still
trigger swapping by cumulative effect.

v2:
   * Fixed dmabuf test.
   * Added test for rejecting read-only.
   * Fixed ioctl detection for latest kernel patch.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 tests/.gitignore          |    1 +
 tests/Makefile.sources    |    1 +
 tests/gem_userptr_blits.c | 1230 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1232 insertions(+)
 create mode 100644 tests/gem_userptr_blits.c

diff --git a/tests/.gitignore b/tests/.gitignore
index cb548a8..a369c8d 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -94,6 +94,7 @@ gem_tiling_max_stride
 gem_unfence_active_buffers
 gem_unref_active_buffers
 gem_vmap_blits
+gem_userptr_blits
 gem_wait_render_timeout
 gem_write_read_ring_switch
 gen3_mixed_blits
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index afb2582..d9d39db 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -119,6 +119,7 @@ TESTS_progs = \
 	gem_unfence_active_buffers \
 	gem_unref_active_buffers \
 	gem_vmap_blits \
+	gem_userptr_blits \
 	gem_wait_render_timeout \
 	gen3_mixed_blits \
 	gen3_render_linear_blits \
diff --git a/tests/gem_userptr_blits.c b/tests/gem_userptr_blits.c
new file mode 100644
index 0000000..1dfdf85
--- /dev/null
+++ b/tests/gem_userptr_blits.c
@@ -0,0 +1,1230 @@
+/*
+ * Copyright © 2009-2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Chris Wilson <chris@chris-wilson.co.uk>
+ *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+ *
+ */
+
+/** @file gem_userptr_blits.c
+ *
+ * This is a test of doing many blits using a mixture of normal system pages
+ * and uncached linear buffers, with a working set larger than the
+ * aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+#include "eviction_common.c"
+
+#define WIDTH 512
+#define HEIGHT 512
+#define PAGE_SIZE 4096
+
+#define LOCAL_I915_GEM_USERPTR       0x34
+#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
+struct local_i915_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint32_t flags;
+#define I915_USERPTR_READ_ONLY (1<<0)
+#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
+	uint32_t handle;
+};
+
+static uint32_t userptr_flags;
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static void gem_userptr_test_unsynchronized(void)
+{
+	userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
+}
+
+static void gem_userptr_test_synchronized(void)
+{
+	userptr_flags = 0;
+}
+
+static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	userptr.user_ptr = (uintptr_t)ptr;
+	userptr.user_size = size;
+	userptr.flags = userptr_flags;
+	if (read_only)
+		userptr.flags |= I915_USERPTR_READ_ONLY;
+
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	if (ret)
+		ret = errno;
+	igt_skip_on_f(ret == ENODEV &&
+		      (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) == 0 &&
+		      !read_only,
+		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
+	if (ret == 0)
+		*handle = userptr.handle;
+
+	return ret;
+}
+
+
+static void gem_userptr_sync(int fd, uint32_t handle)
+{
+	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+}
+
+static void
+copy(int fd, uint32_t dst, uint32_t src, unsigned int error)
+{
+	uint32_t batch[10];
+	struct drm_i915_gem_relocation_entry reloc[2];
+	struct drm_i915_gem_exec_object2 obj[3];
+	struct drm_i915_gem_execbuffer2 exec;
+	uint32_t handle;
+	int ret;
+
+	batch[0] = XY_SRC_COPY_BLT_CMD |
+		  XY_SRC_COPY_BLT_WRITE_ALPHA |
+		  XY_SRC_COPY_BLT_WRITE_RGB | 6;
+	batch[1] = (3 << 24) | /* 32 bits */
+		  (0xcc << 16) | /* copy ROP */
+		  WIDTH*4;
+	batch[2] = 0; /* dst x1,y1 */
+	batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+	batch[4] = 0; /* dst reloc */
+	batch[5] = 0; /* src x1,y1 */
+	batch[6] = WIDTH*4;
+	batch[7] = 0; /* src reloc */
+	batch[8] = MI_BATCH_BUFFER_END;
+	batch[9] = MI_NOOP;
+
+	handle = gem_create(fd, 4096);
+	gem_write(fd, handle, 0, batch, sizeof(batch));
+
+	reloc[0].target_handle = dst;
+	reloc[0].delta = 0;
+	reloc[0].offset = 4 * sizeof(batch[0]);
+	reloc[0].presumed_offset = 0;
+	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
+	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+	reloc[1].target_handle = src;
+	reloc[1].delta = 0;
+	reloc[1].offset = 7 * sizeof(batch[0]);
+	reloc[1].presumed_offset = 0;
+	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
+	reloc[1].write_domain = 0;
+
+	obj[0].handle = dst;
+	obj[0].relocation_count = 0;
+	obj[0].relocs_ptr = 0;
+	obj[0].alignment = 0;
+	obj[0].offset = 0;
+	obj[0].flags = 0;
+	obj[0].rsvd1 = 0;
+	obj[0].rsvd2 = 0;
+
+	obj[1].handle = src;
+	obj[1].relocation_count = 0;
+	obj[1].relocs_ptr = 0;
+	obj[1].alignment = 0;
+	obj[1].offset = 0;
+	obj[1].flags = 0;
+	obj[1].rsvd1 = 0;
+	obj[1].rsvd2 = 0;
+
+	obj[2].handle = handle;
+	obj[2].relocation_count = 2;
+	obj[2].relocs_ptr = (uintptr_t)reloc;
+	obj[2].alignment = 0;
+	obj[2].offset = 0;
+	obj[2].flags = 0;
+	obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+	exec.buffers_ptr = (uintptr_t)obj;
+	exec.buffer_count = 3;
+	exec.batch_start_offset = 0;
+	exec.batch_len = sizeof(batch);
+	exec.DR1 = exec.DR4 = 0;
+	exec.num_cliprects = 0;
+	exec.cliprects_ptr = 0;
+	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+	exec.rsvd1 = exec.rsvd2 = 0;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+	if (ret)
+		ret = errno;
+
+	if (error == ~0)
+		igt_assert(ret != 0);
+	else
+		igt_assert(ret == error);
+
+	gem_close(fd, handle);
+}
+
+static void
+blit(int fd, uint32_t dst, uint32_t src, uint32_t *all_bo, int n_bo, int error)
+{
+	uint32_t batch[12];
+	struct drm_i915_gem_relocation_entry reloc[2];
+	struct drm_i915_gem_exec_object2 *obj;
+	struct drm_i915_gem_execbuffer2 exec;
+	uint32_t handle;
+	int n, ret, i=0;
+
+	batch[i++] = (XY_SRC_COPY_BLT_CMD |
+		    XY_SRC_COPY_BLT_WRITE_ALPHA |
+		    XY_SRC_COPY_BLT_WRITE_RGB | 6);
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i - 1] += 2;
+	batch[i++] = (3 << 24) | /* 32 bits */
+		  (0xcc << 16) | /* copy ROP */
+		  WIDTH*4;
+	batch[i++] = 0; /* dst x1,y1 */
+	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+	batch[i++] = 0; /* dst reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0; /* FIXME */
+	batch[i++] = 0; /* src x1,y1 */
+	batch[i++] = WIDTH*4;
+	batch[i++] = 0; /* src reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0; /* FIXME */
+	batch[i++] = MI_BATCH_BUFFER_END;
+	batch[i++] = MI_NOOP;
+
+	handle = gem_create(fd, 4096);
+	gem_write(fd, handle, 0, batch, sizeof(batch));
+
+	reloc[0].target_handle = dst;
+	reloc[0].delta = 0;
+	reloc[0].offset = 4 * sizeof(batch[0]);
+	reloc[0].presumed_offset = 0;
+	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+	reloc[1].target_handle = src;
+	reloc[1].delta = 0;
+	reloc[1].offset = 7 * sizeof(batch[0]);
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		reloc[1].offset += sizeof(batch[0]);
+	reloc[1].presumed_offset = 0;
+	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc[1].write_domain = 0;
+
+	obj = calloc(n_bo + 1, sizeof(*obj));
+	for (n = 0; n < n_bo; n++)
+		obj[n].handle = all_bo[n];
+	obj[n].handle = handle;
+	obj[n].relocation_count = 2;
+	obj[n].relocs_ptr = (uintptr_t)reloc;
+
+	exec.buffers_ptr = (uintptr_t)obj;
+	exec.buffer_count = n_bo + 1;
+	exec.batch_start_offset = 0;
+	exec.batch_len = i * 4;
+	exec.DR1 = exec.DR4 = 0;
+	exec.num_cliprects = 0;
+	exec.cliprects_ptr = 0;
+	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+	i915_execbuffer2_set_context_id(exec, 0);
+	exec.rsvd2 = 0;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+	if (ret)
+		ret = errno;
+
+	igt_assert(ret == error);
+
+	gem_close(fd, handle);
+	free(obj);
+}
+
+static uint32_t
+create_userptr(int fd, uint32_t val, uint32_t *ptr)
+{
+	uint32_t handle;
+	int i, ret;
+
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
+	igt_assert(ret == 0);
+	igt_assert(handle != 0);
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		ptr[i] = val++;
+
+	return handle;
+}
+
+static void **handle_ptr_map;
+static unsigned int num_handle_ptr_map;
+
+static void add_handle_ptr(uint32_t handle, void *ptr)
+{
+	if (handle >= num_handle_ptr_map) {
+		handle_ptr_map = realloc(handle_ptr_map,
+					 (handle + 1000) * sizeof(void*));
+		num_handle_ptr_map = handle + 1000;
+	}
+
+	handle_ptr_map[handle] = ptr;
+}
+
+static void *get_handle_ptr(uint32_t handle)
+{
+	return handle_ptr_map[handle];
+}
+
+static void free_handle_ptr(uint32_t handle)
+{
+	igt_assert(handle < num_handle_ptr_map);
+	igt_assert(handle_ptr_map[handle]);
+
+	free(handle_ptr_map[handle]);
+	handle_ptr_map[handle] = NULL;
+}
+
+static uint32_t create_userptr_bo(int fd, int size)
+{
+	void *ptr;
+	uint32_t handle;
+	int ret;
+
+	ret = posix_memalign(&ptr, PAGE_SIZE, size);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
+	igt_assert(ret == 0);
+	add_handle_ptr(handle, ptr);
+
+	return handle;
+}
+
+static void clear(int fd, uint32_t handle, int size)
+{
+	void *ptr = get_handle_ptr(handle);
+
+	igt_assert(ptr != NULL);
+
+	memset(ptr, 0, size);
+}
+
+static void free_userptr_bo(int fd, uint32_t handle)
+{
+	gem_close(fd, handle);
+	free_handle_ptr(handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+	uint32_t handle;
+	int i;
+
+	handle = gem_create(fd, sizeof(linear));
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		linear[i] = val++;
+	gem_write(fd, handle, 0, linear, sizeof(linear));
+
+	return handle;
+}
+
+static void
+check_cpu(uint32_t *ptr, uint32_t val)
+{
+	int i;
+
+	for (i = 0; i < WIDTH*HEIGHT; i++) {
+		if (ptr[i] != val) {
+			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+				"at offset 0x%08x\n",
+				val, ptr[i], i * 4);
+			abort();
+		}
+		val++;
+	}
+}
+
+static void
+check_gpu(int fd, uint32_t handle, uint32_t val)
+{
+	gem_read(fd, handle, 0, linear, sizeof(linear));
+	check_cpu(linear, val);
+}
+
+static int has_userptr(int fd)
+{
+	uint32_t handle = 0;
+	void *ptr;
+	uint32_t oldflags;
+	int ret;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+	oldflags = userptr_flags;
+	gem_userptr_test_unsynchronized();
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	userptr_flags = oldflags;
+	if (ret != 0) {
+		free(ptr);
+		return 0;
+	}
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return handle != 0;
+}
+
+static int test_input_checking(int fd)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	/* Invalid flags. */
+	userptr.user_ptr = 0;
+	userptr.user_size = 0;
+	userptr.flags = ~0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	/* Too big. */
+	userptr.user_ptr = 0;
+	userptr.user_size = ~0;
+	userptr.flags = 0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	/* Both wrong. */
+	userptr.user_ptr = 0;
+	userptr.user_size = ~0;
+	userptr.flags = ~0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	return 0;
+}
+
+static int test_access_control(int fd)
+{
+	igt_fork(child, 1) {
+		void *ptr;
+		int ret;
+		uint32_t handle;
+
+		igt_drop_root();
+
+		/* CAP_SYS_ADMIN is needed for UNSYNCHRONIZED mappings. */
+		gem_userptr_test_unsynchronized();
+
+		igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+		ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+		if (ret == 0)
+			gem_close(fd, handle);
+		free(ptr);
+		igt_assert(ret == EPERM);
+	}
+
+	igt_waitchildren();
+
+	return 0;
+}
+
+static int test_invalid_mapping(int fd)
+{
+	int ret;
+	uint32_t handle, handle2;
+	void *ptr;
+
+	/* NULL pointer. */
+	ret = gem_userptr(fd, NULL, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
+	gem_close(fd, handle);
+
+	/* GTT mapping */
+	handle = create_bo(fd, 0);
+	ptr = gem_mmap__gtt(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
+	if (ptr == NULL)
+		gem_close(fd, handle);
+	assert(ptr != NULL);
+	assert(((unsigned long)ptr & (PAGE_SIZE - 1)) == 0);
+	assert((sizeof(linear) & (PAGE_SIZE - 1)) == 0);
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle2);
+	igt_assert(ret == 0);
+	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
+	gem_close(fd, handle2);
+	munmap(ptr, sizeof(linear));
+	gem_close(fd, handle);
+
+	return 0;
+}
+
+static int test_forbidden_ops(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+	char buf[PAGE_SIZE];
+	struct drm_i915_gem_pread gem_pread;
+	struct drm_i915_gem_pwrite gem_pwrite;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	gem_pread.handle = handle;
+	gem_pread.offset = 0;
+	gem_pread.size = PAGE_SIZE;
+	gem_pread.data_ptr = (uintptr_t)buf;
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
+	if (ret == 0) {
+		gem_close(fd, handle);
+		free(ptr);
+	}
+	igt_assert(ret != 0);
+
+	gem_pwrite.handle = handle;
+	gem_pwrite.offset = 0;
+	gem_pwrite.size = PAGE_SIZE;
+	gem_pwrite.data_ptr = (uintptr_t)buf;
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
+	if (ret == 0) {
+		gem_close(fd, handle);
+		free(ptr);
+	}
+	igt_assert(ret != 0);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static char counter;
+
+static void (*orig_sigbus)(int sig, siginfo_t *info, void *param);
+static unsigned long sigbus_start;
+static long sigbus_cnt = -1;
+
+static void
+check_bo(int fd1, uint32_t handle1, int is_userptr, int fd2, uint32_t handle2)
+{
+	char *ptr1, *ptr2;
+	int i;
+	unsigned long size = sizeof(linear);
+
+	if (is_userptr)
+		ptr1 = get_handle_ptr(handle1);
+	else
+		ptr1 = gem_mmap(fd1, handle1, sizeof(linear), PROT_READ | PROT_WRITE);
+
+	ptr2 = gem_mmap(fd2, handle2, sizeof(linear), PROT_READ | PROT_WRITE);
+
+	igt_assert(ptr1);
+	igt_assert(ptr2);
+
+	sigbus_start = ptr2;
+
+	if (sigbus_cnt == 0)
+		size = 1;
+
+	/* check whether it's still our old object first. */
+	for (i = 0; i < size; i++) {
+		igt_assert(ptr1[i] == counter);
+		igt_assert(ptr2[i] == counter);
+	}
+
+	counter++;
+
+	if (size > 1) {
+		memset(ptr1, counter, size);
+		igt_assert(memcmp(ptr1, ptr2, size) == 0);
+	}
+
+	if (!is_userptr)
+		munmap(ptr1, sizeof(linear));
+	munmap(ptr2, sizeof(linear));
+}
+
+static int export_handle(int fd, uint32_t handle, int *outfd)
+{
+	struct drm_prime_handle args;
+	int ret;
+
+	args.handle = handle;
+	args.flags = DRM_CLOEXEC;
+	args.fd = -1;
+
+	ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
+	if (ret)
+		ret = errno;
+	*outfd = args.fd;
+
+	return ret;
+}
+
+static void sigbus(int sig, siginfo_t *info, void *param)
+{
+	unsigned long ptr = (unsigned long)info->si_addr;
+	void *addr;
+
+	if (ptr >= sigbus_start &&
+	    ptr <= (sigbus_start + sizeof(linear))) {
+		sigbus_cnt++;
+		addr = mmap((void *)ptr, sizeof(linear), PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
+		if ((unsigned long)addr == ptr) {
+			memset(addr, counter, sizeof(linear));
+			return;
+		}
+	}
+
+	if (orig_sigbus)
+		orig_sigbus(sig, info, param);
+	assert(0);
+}
+
+static int test_dmabuf(void)
+{
+	int fd1, fd2;
+	uint32_t handle, handle_import1, handle_import2, handle_selfimport;
+	int dma_buf_fd = -1;
+	int ret;
+	struct sigaction sigact, orig_sigact;
+
+	fd1 = drm_open_any();
+	fd2 = drm_open_any();
+
+	handle = create_userptr_bo(fd1, sizeof(linear));
+
+	ret = export_handle(fd1, handle, &dma_buf_fd);
+	if (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) {
+		igt_assert(ret == EINVAL);
+		free_userptr_bo(fd1, handle);
+
+		return 0;
+	} else {
+		igt_assert(ret == 0);
+		igt_assert(dma_buf_fd >= 0);
+	}
+	handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd);
+	check_bo(fd1, handle, 1, fd2, handle_import1);
+
+	/* reimport should give us the same handle so that userspace can check
+	 * whether it has that bo already somewhere. */
+	handle_import2 = prime_fd_to_handle(fd2, dma_buf_fd);
+	igt_assert(handle_import1 == handle_import2);
+
+	/* Same for re-importing on the exporting fd. */
+	handle_selfimport = prime_fd_to_handle(fd1, dma_buf_fd);
+	igt_assert(handle == handle_selfimport);
+
+	/* close dma_buf, check whether nothing disappears. */
+	close(dma_buf_fd);
+	check_bo(fd1, handle, 1, fd2, handle_import1);
+
+	/* destroy userptr object and expect SIGBUS */
+	free_userptr_bo(fd1, handle);
+	sigact.sa_sigaction = sigbus;
+	sigact.sa_flags = SA_SIGINFO;
+	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
+	assert(ret == 0);
+	orig_sigbus = orig_sigact.sa_sigaction;
+	sigbus_cnt = 0;
+	check_bo(fd2, handle_import1, 0, fd2, handle_import1);
+	assert(sigbus_cnt > 0);
+	sigact.sa_sigaction = orig_sigbus;
+	sigact.sa_flags = SA_SIGINFO;
+	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
+	assert(ret == 0);
+
+	gem_close(fd2, handle_import1);
+	close(fd1);
+	close(fd2);
+
+	return 0;
+}
+
+static int test_usage_restrictions(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE * 2) == 0);
+
+	/* Address not aligned. */
+	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Size not rounded to page size. */
+	ret = gem_userptr(fd, ptr, PAGE_SIZE - 1, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Both wrong. */
+	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE - 1, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Read-only not supported. */
+	ret = gem_userptr(fd, (char *)ptr, PAGE_SIZE, 1, &handle);
+	igt_assert(ret != 0);
+
+	free(ptr);
+
+	return 0;
+}
+
+static int test_create_destroy(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+
+	igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static int test_coherency(int fd, int count)
+{
+	uint32_t *memory;
+	uint32_t *cpu, *cpu_val;
+	uint32_t *gpu, *gpu_val;
+	uint32_t start = 0;
+	int i, ret;
+
+	printf("Using 2x%d 1MiB buffers\n", count);
+
+	ret = posix_memalign((void **)&memory, PAGE_SIZE, count*sizeof(linear));
+	if (ret != 0 || memory == NULL) {
+		fprintf(stderr, "Unable to allocate %lld bytes\n",
+			(long long)count*sizeof(linear));
+		return 1;
+	}
+
+	gpu = malloc(sizeof(uint32_t)*count*4);
+	gpu_val = gpu + count;
+	cpu = gpu_val + count;
+	cpu_val = cpu + count;
+
+	for (i = 0; i < count; i++) {
+		gpu[i] = create_bo(fd, start);
+		gpu_val[i] = start;
+		start += WIDTH*HEIGHT;
+	}
+
+	for (i = 0; i < count; i++) {
+		cpu[i] = create_userptr(fd, start, memory+i*WIDTH*HEIGHT);
+		cpu_val[i] = start;
+		start += WIDTH*HEIGHT;
+	}
+
+	printf("Verifying initialisation...\n");
+	for (i = 0; i < count; i++) {
+		check_gpu(fd, gpu[i], gpu_val[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+	}
+
+	printf("Cyclic blits cpu->gpu, forward...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = i % count;
+		int dst = (i + 1) % count;
+
+		copy(fd, gpu[dst], cpu[src], 0);
+		gpu_val[dst] = cpu_val[src];
+	}
+	for (i = 0; i < count; i++)
+		check_gpu(fd, gpu[i], gpu_val[i]);
+
+	printf("Cyclic blits gpu->cpu, backward...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = (i + 1) % count;
+		int dst = i % count;
+
+		copy(fd, cpu[dst], gpu[src], 0);
+		cpu_val[dst] = gpu_val[src];
+	}
+	for (i = 0; i < count; i++) {
+		gem_userptr_sync(fd, cpu[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+	}
+
+	printf("Random blits...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = random() % count;
+		int dst = random() % count;
+
+		if (random() & 1) {
+			copy(fd, gpu[dst], cpu[src], 0);
+			gpu_val[dst] = cpu_val[src];
+		} else {
+			copy(fd, cpu[dst], gpu[src], 0);
+			cpu_val[dst] = gpu_val[src];
+		}
+	}
+	for (i = 0; i < count; i++) {
+		check_gpu(fd, gpu[i], gpu_val[i]);
+		gem_close(fd, gpu[i]);
+
+		gem_userptr_sync(fd, cpu[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+		gem_close(fd, cpu[i]);
+	}
+
+	free(gpu);
+	free(memory);
+
+	return 0;
+}
+
+static struct igt_eviction_test_ops fault_ops = {
+	.create = create_userptr_bo,
+	.close = free_userptr_bo,
+	.copy = blit,
+	.clear = clear,
+};
+
+static int can_swap(void)
+{
+	unsigned long as, ram;
+
+	/* Cannot swap if not enough address space */
+
+	/* FIXME: Improve check criteria. */
+	if (sizeof(void*) < 8)
+		as = 3 * 1024;
+	else
+		as = 256 * 1024; /* Just a big number */
+
+	ram = intel_get_total_ram_mb();
+
+	if ((as - 128) < (ram - 256))
+		return 0;
+
+	return 1;
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static void test_forking_evictions(int fd, int size, int count,
+			     unsigned flags)
+{
+	int trash_count;
+	int num_threads;
+
+	trash_count = intel_get_total_ram_mb() * 11 / 10;
+	/* Use the fact test will spawn a number of child
+	 * processes meaning swapping will be triggered system
+	 * wide even if one process on it's own can't do it.
+	 */
+	num_threads = min(sysconf(_SC_NPROCESSORS_ONLN) * 4, 12);
+	trash_count /= num_threads;
+	if (count > trash_count)
+		count = trash_count;
+
+	forking_evictions(fd, &fault_ops, size, count, trash_count, flags);
+}
+
+static void test_swapping_evictions(int fd, int size, int count)
+{
+	int trash_count;
+
+	igt_skip_on_f(!can_swap(),
+		"Not enough process address space for swapping tests.\n");
+
+	trash_count = intel_get_total_ram_mb() * 11 / 10;
+
+	swapping_evictions(fd, &fault_ops, size, count, trash_count);
+}
+
+static void test_minor_evictions(int fd, int size, int count)
+{
+	minor_evictions(fd, &fault_ops, size, count);
+}
+
+static void test_major_evictions(int fd, int size, int count)
+{
+	major_evictions(fd, &fault_ops, size, count);
+}
+
+static int test_overlap(int fd, int expected)
+{
+	char *ptr;
+	int ret;
+	uint32_t handle, handle2;
+
+	igt_assert(posix_memalign((void *)&ptr, PAGE_SIZE, PAGE_SIZE * 3) == 0);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle2);
+	igt_assert(ret == 0);
+	gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE * 2, PAGE_SIZE, 0, &handle2);
+	igt_assert(ret == 0);
+	gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE * 2, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE * 2, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE * 3, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static int test_unmap(int fd, int expected)
+{
+	char *ptr, *bo_ptr;
+	const unsigned int num_obj = 3;
+	unsigned int i;
+	uint32_t bo[num_obj + 1];
+	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
+	int ret;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+						& ~(PAGE_SIZE - 1));
+
+	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
+		igt_assert(ret == 0);
+	}
+
+	bo[num_obj] = create_bo(fd, 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], 0);
+
+	ret = munmap(ptr, map_size);
+	assert(ret == 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], expected);
+
+	for (i = 0; i < (num_obj + 1); i++)
+		gem_close(fd, bo[i]);
+
+	return 0;
+}
+
+static int test_unmap_after_close(int fd)
+{
+	char *ptr, *bo_ptr;
+	const unsigned int num_obj = 3;
+	unsigned int i;
+	uint32_t bo[num_obj + 1];
+	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
+	int ret;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+						& ~(PAGE_SIZE - 1));
+
+	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
+		igt_assert(ret == 0);
+	}
+
+	bo[num_obj] = create_bo(fd, 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], 0);
+
+	for (i = 0; i < (num_obj + 1); i++)
+		gem_close(fd, bo[i]);
+
+	ret = munmap(ptr, map_size);
+	assert(ret == 0);
+
+	return 0;
+}
+
+static int test_unmap_cycles(int fd, int expected)
+{
+	int i;
+
+	for (i = 0; i < 1000; i++)
+		test_unmap(fd, expected);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	uint64_t aperture_size;
+	unsigned int total_ram;
+	int fd = -1, count = 0, size = 0, ret;
+
+	igt_skip_on_simulation();
+
+	igt_subtest_init(argc, argv);
+
+	igt_fixture {
+		fd = drm_open_any();
+		igt_assert(fd >= 0);
+
+		ret = has_userptr(fd);
+		igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
+			      strerror(errno), ret);
+
+		size = sizeof(linear);
+
+		aperture_size = gem_aperture_size(fd);
+		printf("Aperture size is %lu MiB\n", (long)(aperture_size / (1024*1024)));
+
+		if (argc > 1)
+			count = atoi(argv[1]);
+		if (count == 0)
+			count = 2 * aperture_size / (1024*1024) / 3;
+
+		total_ram = intel_get_total_ram_mb();
+		printf("Total RAM is %u MiB\n", total_ram);
+
+		if (count > total_ram * 3 / 4) {
+			count = intel_get_total_ram_mb() * 3 / 4;
+			printf("Not enough RAM to run test, reducing buffer count.\n");
+		}
+	}
+
+	igt_subtest("input-checking")
+		test_input_checking(fd);
+
+	igt_subtest("usage-restrictions")
+		test_usage_restrictions(fd);
+
+	igt_subtest("invalid-mapping")
+		test_invalid_mapping(fd);
+
+	igt_subtest("forbidden-operations")
+		test_forbidden_ops(fd);
+
+	printf("Testing unsynchronized mappings...\n");
+	gem_userptr_test_unsynchronized();
+
+	igt_subtest("create-destroy-unsync")
+		test_create_destroy(fd);
+
+	igt_subtest("unsync-overlap")
+		test_overlap(fd, 0);
+
+	igt_subtest("unsync-unmap")
+		test_unmap(fd, 0);
+
+	igt_subtest("unsync-unmap-cycles")
+		test_unmap_cycles(fd, 0);
+
+	igt_subtest("unsync-unmap-after-close")
+		test_unmap_after_close(fd);
+
+	igt_subtest("coherency-unsync")
+		test_coherency(fd, count);
+
+	igt_subtest("dmabuf-unsync")
+		test_dmabuf();
+
+	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
+		igt_subtest_f("forked-unsync%s%s%s-%s",
+		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
+		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
+		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
+				"-mempressure" : "",
+		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
+				"interruptible" : "normal") {
+			test_forking_evictions(fd, size, count, flags);
+		}
+	}
+
+	igt_subtest("swapping-unsync-normal")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-unsync-normal")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-unsync-normal") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_fixture {
+		size = sizeof(linear);
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	igt_fork_signal_helper();
+
+	igt_subtest("swapping-unsync-interruptible")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-unsync-interruptible")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-unsync-interruptible") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_stop_signal_helper();
+
+	printf("Testing synchronized mappings...\n");
+
+	igt_fixture {
+		size = sizeof(linear);
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	gem_userptr_test_synchronized();
+
+	igt_subtest("create-destroy-sync")
+		test_create_destroy(fd);
+
+	igt_subtest("sync-overlap")
+		test_overlap(fd, EINVAL);
+
+	igt_subtest("sync-unmap")
+		test_unmap(fd, EFAULT);
+
+	igt_subtest("sync-unmap-cycles")
+		test_unmap_cycles(fd, EFAULT);
+
+	igt_subtest("sync-unmap-after-close")
+		test_unmap_after_close(fd);
+
+	igt_subtest("coherency-sync")
+		test_coherency(fd, count);
+
+	igt_subtest("dmabuf-sync")
+		test_dmabuf();
+
+	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
+		igt_subtest_f("forked-sync%s%s%s-%s",
+		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
+		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
+		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
+				"-mempressure" : "",
+		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
+				"interruptible" : "normal") {
+			test_forking_evictions(fd, size, count, flags);
+		}
+	}
+
+	igt_subtest("swapping-normal-sync")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-normal-sync")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-normal-sync") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_fixture {
+		size = 1024 * 1024;
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	igt_fork_signal_helper();
+
+	igt_subtest("swapping-sync-interruptible")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-sync-interruptible")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-sync-interruptible") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_stop_signal_helper();
+
+	igt_subtest("access-control")
+	test_access_control(fd);
+
+	igt_exit();
+
+	return 0;
+}
-- 
1.9.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case
  2014-02-26 16:17 [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
  2014-02-26 16:17 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
@ 2014-02-26 16:17 ` Tvrtko Ursulin
  2014-02-26 16:17 ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-02-26 16:17 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

No need for the old test case once the new one was added.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 tests/.gitignore       |   1 -
 tests/Makefile.sources |   1 -
 tests/gem_vmap_blits.c | 344 -------------------------------------------------
 3 files changed, 346 deletions(-)
 delete mode 100644 tests/gem_vmap_blits.c

diff --git a/tests/.gitignore b/tests/.gitignore
index a369c8d..84a1d7e 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -93,7 +93,6 @@ gem_tiled_swapping
 gem_tiling_max_stride
 gem_unfence_active_buffers
 gem_unref_active_buffers
-gem_vmap_blits
 gem_userptr_blits
 gem_wait_render_timeout
 gem_write_read_ring_switch
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index d9d39db..e89f20a 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -118,7 +118,6 @@ TESTS_progs = \
 	gem_tiling_max_stride \
 	gem_unfence_active_buffers \
 	gem_unref_active_buffers \
-	gem_vmap_blits \
 	gem_userptr_blits \
 	gem_wait_render_timeout \
 	gen3_mixed_blits \
diff --git a/tests/gem_vmap_blits.c b/tests/gem_vmap_blits.c
deleted file mode 100644
index 48297af..0000000
--- a/tests/gem_vmap_blits.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright © 2009,2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *    Chris Wilson <chris@chris-wilson.co.uk>
- *
- */
-
-/** @file gem_vmap_blits.c
- *
- * This is a test of doing many blits using a mixture of normal system pages
- * and uncached linear buffers, with a working set larger than the
- * aperture size.
- *
- * The goal is to simply ensure the basics work.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include "drm.h"
-#include "i915_drm.h"
-#include "drmtest.h"
-#include "intel_bufmgr.h"
-#include "intel_batchbuffer.h"
-#include "intel_gpu_tools.h"
-
-#if !defined(I915_PARAM_HAS_VMAP)
-#pragma message("No vmap support in drm, skipping")
-int main(int argc, char **argv)
-{
-	fprintf(stderr, "No vmap support in drm.\n");
-	return 77;
-}
-#else
-
-#define WIDTH 512
-#define HEIGHT 512
-
-static uint32_t linear[WIDTH*HEIGHT];
-
-static uint32_t gem_vmap(int fd, void *ptr, int size, int read_only)
-{
-	struct drm_i915_gem_vmap vmap;
-
-	vmap.user_ptr = (uintptr_t)ptr;
-	vmap.user_size = size;
-	vmap.flags = 0;
-	if (read_only)
-		vmap.flags |= I915_VMAP_READ_ONLY;
-
-	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_VMAP, &vmap))
-		return 0;
-
-	return vmap.handle;
-}
-
-
-static void gem_vmap_sync(int fd, uint32_t handle)
-{
-	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
-}
-
-static void
-copy(int fd, uint32_t dst, uint32_t src)
-{
-	uint32_t batch[10];
-	struct drm_i915_gem_relocation_entry reloc[2];
-	struct drm_i915_gem_exec_object2 obj[3];
-	struct drm_i915_gem_execbuffer2 exec;
-	uint32_t handle;
-	int ret;
-
-	batch[0] = XY_SRC_COPY_BLT_CMD |
-		  XY_SRC_COPY_BLT_WRITE_ALPHA |
-		  XY_SRC_COPY_BLT_WRITE_RGB | 6;
-	batch[1] = (3 << 24) | /* 32 bits */
-		  (0xcc << 16) | /* copy ROP */
-		  WIDTH*4;
-	batch[2] = 0; /* dst x1,y1 */
-	batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
-	batch[4] = 0; /* dst reloc */
-	batch[5] = 0; /* src x1,y1 */
-	batch[6] = WIDTH*4;
-	batch[7] = 0; /* src reloc */
-	batch[8] = MI_BATCH_BUFFER_END;
-	batch[9] = MI_NOOP;
-
-	handle = gem_create(fd, 4096);
-	gem_write(fd, handle, 0, batch, sizeof(batch));
-
-	reloc[0].target_handle = dst;
-	reloc[0].delta = 0;
-	reloc[0].offset = 4 * sizeof(batch[0]);
-	reloc[0].presumed_offset = 0;
-	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
-	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
-
-	reloc[1].target_handle = src;
-	reloc[1].delta = 0;
-	reloc[1].offset = 7 * sizeof(batch[0]);
-	reloc[1].presumed_offset = 0;
-	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
-	reloc[1].write_domain = 0;
-
-	obj[0].handle = dst;
-	obj[0].relocation_count = 0;
-	obj[0].relocs_ptr = 0;
-	obj[0].alignment = 0;
-	obj[0].offset = 0;
-	obj[0].flags = 0;
-	obj[0].rsvd1 = 0;
-	obj[0].rsvd2 = 0;
-
-	obj[1].handle = src;
-	obj[1].relocation_count = 0;
-	obj[1].relocs_ptr = 0;
-	obj[1].alignment = 0;
-	obj[1].offset = 0;
-	obj[1].flags = 0;
-	obj[1].rsvd1 = 0;
-	obj[1].rsvd2 = 0;
-
-	obj[2].handle = handle;
-	obj[2].relocation_count = 2;
-	obj[2].relocs_ptr = (uintptr_t)reloc;
-	obj[2].alignment = 0;
-	obj[2].offset = 0;
-	obj[2].flags = 0;
-	obj[2].rsvd1 = obj[2].rsvd2 = 0;
-
-	exec.buffers_ptr = (uintptr_t)obj;
-	exec.buffer_count = 3;
-	exec.batch_start_offset = 0;
-	exec.batch_len = sizeof(batch);
-	exec.DR1 = exec.DR4 = 0;
-	exec.num_cliprects = 0;
-	exec.cliprects_ptr = 0;
-	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
-	exec.rsvd1 = exec.rsvd2 = 0;
-
-	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
-	while (ret && errno == EBUSY) {
-		drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
-		ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
-	}
-	igt_assert(ret == 0);
-
-	gem_close(fd, handle);
-}
-
-static uint32_t
-create_vmap(int fd, uint32_t val, uint32_t *ptr)
-{
-	uint32_t handle;
-	int i;
-
-	handle = gem_vmap(fd, ptr, sizeof(linear), 0);
-
-	/* Fill the BO with dwords starting at val */
-	for (i = 0; i < WIDTH*HEIGHT; i++)
-		ptr[i] = val++;
-
-	return handle;
-}
-
-static uint32_t
-create_bo(int fd, uint32_t val)
-{
-	uint32_t handle;
-	int i;
-
-	handle = gem_create(fd, sizeof(linear));
-
-	/* Fill the BO with dwords starting at val */
-	for (i = 0; i < WIDTH*HEIGHT; i++)
-		linear[i] = val++;
-	gem_write(fd, handle, 0, linear, sizeof(linear));
-
-	return handle;
-}
-
-static void
-check_cpu(uint32_t *ptr, uint32_t val)
-{
-	int i;
-
-	for (i = 0; i < WIDTH*HEIGHT; i++) {
-		if (ptr[i] != val) {
-			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
-				"at offset 0x%08x\n",
-				val, ptr[i], i * 4);
-			abort();
-		}
-		val++;
-	}
-}
-
-static void
-check_gpu(int fd, uint32_t handle, uint32_t val)
-{
-	gem_read(fd, handle, 0, linear, sizeof(linear));
-	check_cpu(linear, val);
-}
-
-static int has_vmap(int fd)
-{
-	drm_i915_getparam_t gp;
-	int i;
-
-	gp.param = I915_PARAM_HAS_VMAP;
-	gp.value = &i;
-
-	return drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0 && i > 0;
-}
-
-int main(int argc, char **argv)
-{
-	uint32_t *memory;
-	uint32_t *cpu, *cpu_val;
-	uint32_t *gpu, *gpu_val;
-	uint32_t start = 0;
-	int i, fd, count;
-
-	igt_simple_init();
-
-	igt_skip_on_simulation();
-
-	fd = drm_open_any();
-
-	if (!has_vmap(fd)) {
-		fprintf(stderr, "No vmap support, ignoring.\n");
-		return 77;
-	}
-
-	count = 0;
-	if (argc > 1)
-		count = atoi(argv[1]);
-	if (count == 0)
-		count = 3 * gem_aperture_size(fd) / (1024*1024) / 4;
-	printf("Using 2x%d 1MiB buffers\n", count);
-
-	memory = malloc(count*sizeof(linear));
-	if (memory == NULL) {
-		fprintf(stderr, "Unable to allocate %lld bytes\n",
-			(long long)count*sizeof(linear));
-		return 1;
-	}
-
-	gpu = malloc(sizeof(uint32_t)*count*4);
-	gpu_val = gpu + count;
-	cpu = gpu_val + count;
-	cpu_val = cpu + count;
-
-	for (i = 0; i < count; i++) {
-		gpu[i] = create_bo(fd, start);
-		gpu_val[i] = start;
-		start += WIDTH*HEIGHT;
-	}
-
-	for (i = 0; i < count; i++) {
-		cpu[i] = create_vmap(fd, start, memory+i*WIDTH*HEIGHT);
-		cpu_val[i] = start;
-		start += WIDTH*HEIGHT;;
-	}
-
-	printf("Verifying initialisation...\n");
-	for (i = 0; i < count; i++) {
-		check_gpu(fd, gpu[i], gpu_val[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	printf("Cyclic blits cpu->gpu, forward...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = i % count;
-		int dst = (i + 1) % count;
-
-		copy(fd, gpu[dst], cpu[src]);
-		gpu_val[dst] = cpu_val[src];
-	}
-	for (i = 0; i < count; i++)
-		check_gpu(fd, gpu[i], gpu_val[i]);
-
-	printf("Cyclic blits gpu->cpu, backward...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = (i + 1) % count;
-		int dst = i % count;
-
-		copy(fd, cpu[dst], gpu[src]);
-		cpu_val[dst] = gpu_val[src];
-	}
-	for (i = 0; i < count; i++) {
-		gem_vmap_sync(fd, cpu[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	printf("Random blits...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = random() % count;
-		int dst = random() % count;
-
-		if (random() & 1) {
-			copy(fd, gpu[dst], cpu[src]);
-			gpu_val[dst] = cpu_val[src];
-		} else {
-			copy(fd, cpu[dst], gpu[src]);
-			cpu_val[dst] = gpu_val[src];
-		}
-	}
-	for (i = 0; i < count; i++) {
-		check_gpu(fd, gpu[i], gpu_val[i]);
-		gem_vmap_sync(fd, cpu[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	return 0;
-}
-
-#endif
-- 
1.9.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-02-26 16:17 [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
  2014-02-26 16:17 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
  2014-02-26 16:17 ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
@ 2014-02-26 16:17 ` Tvrtko Ursulin
  2014-03-19 11:13 ` [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-02-26 16:17 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This adds a small benchmark for the new userptr functionality.

Apart from basic surface creation and destruction, also tested is the
impact of having userptr surfaces in the process address space. Reason
for that is the impact of MMU notifiers on common address space
operations like munmap() which is per process.

v2:
  * Moved to benchmarks.
  * Added pointer read/write tests.
  * Changed output to say iterations per second instead of
    operations per second.
  * Multiply result by batch size for multi-create* tests
    for a more comparable number with create-destroy test.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
---
 Android.mk                         |   3 +-
 benchmarks/.gitignore              |   1 +
 benchmarks/Android.mk              |  36 +++
 benchmarks/Makefile.am             |   7 +-
 benchmarks/Makefile.sources        |   6 +
 benchmarks/gem_userptr_benchmark.c | 513 +++++++++++++++++++++++++++++++++++++
 6 files changed, 558 insertions(+), 8 deletions(-)
 create mode 100644 benchmarks/Android.mk
 create mode 100644 benchmarks/Makefile.sources
 create mode 100644 benchmarks/gem_userptr_benchmark.c

diff --git a/Android.mk b/Android.mk
index 8aeb2d4..0c969b8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,2 +1 @@
-include $(call all-named-subdir-makefiles, lib tests tools)
-
+include $(call all-named-subdir-makefiles, lib tests tools benchmarks)
diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
index ddea6f7..09e5bd8 100644
--- a/benchmarks/.gitignore
+++ b/benchmarks/.gitignore
@@ -1,3 +1,4 @@
+gem_userptr_benchmark
 intel_upload_blit_large
 intel_upload_blit_large_gtt
 intel_upload_blit_large_map
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
new file mode 100644
index 0000000..5bb8ef5
--- /dev/null
+++ b/benchmarks/Android.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(LOCAL_PATH)/Makefile.sources
+
+#================#
+
+define add_benchmark
+    include $(CLEAR_VARS)
+
+    LOCAL_SRC_FILES := $1.c
+
+    LOCAL_CFLAGS += -DHAVE_STRUCT_SYSINFO_TOTALRAM
+    LOCAL_CFLAGS += -DANDROID -UNDEBUG -include "check-ndebug.h"
+    LOCAL_CFLAGS += -std=c99
+    # FIXME: drop once Bionic correctly annotates "noreturn" on pthread_exit
+    LOCAL_CFLAGS += -Wno-error=return-type
+    # Excessive complaining for established cases. Rely on the Linux version warnings.
+    LOCAL_CFLAGS += -Wno-sign-compare
+
+    LOCAL_MODULE := $1
+    LOCAL_MODULE_TAGS := optional
+
+    LOCAL_STATIC_LIBRARIES := libintel_gpu_tools
+
+    LOCAL_SHARED_LIBRARIES := libpciaccess  \
+                              libdrm        \
+                              libdrm_intel
+
+    include $(BUILD_EXECUTABLE)
+endef
+
+#================#
+
+benchmark_list := $(bin_PROGRAMS)
+
+$(foreach item,$(benchmark_list),$(eval $(call add_benchmark,$(item))))
diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
index e2ad784..d173bf4 100644
--- a/benchmarks/Makefile.am
+++ b/benchmarks/Makefile.am
@@ -1,9 +1,4 @@
-
-bin_PROGRAMS = 				\
-	intel_upload_blit_large		\
-	intel_upload_blit_large_gtt	\
-	intel_upload_blit_large_map	\
-	intel_upload_blit_small
+include Makefile.sources
 
 AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
 AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS)
diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
new file mode 100644
index 0000000..fd6c107
--- /dev/null
+++ b/benchmarks/Makefile.sources
@@ -0,0 +1,6 @@
+bin_PROGRAMS =                          \
+        intel_upload_blit_large         \
+        intel_upload_blit_large_gtt     \
+        intel_upload_blit_large_map     \
+        intel_upload_blit_small         \
+        gem_userptr_benchmark
diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
new file mode 100644
index 0000000..dc36f59
--- /dev/null
+++ b/benchmarks/gem_userptr_benchmark.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+ *
+ */
+
+/** @file gem_userptr_benchmark.c
+ *
+ * Benchmark the userptr code and impact of having userptr surfaces
+ * in process address space on some normal operations.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+#define WIDTH 128
+#define HEIGHT 128
+#define PAGE_SIZE 4096
+
+#define LOCAL_I915_GEM_USERPTR       0x34
+#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
+struct local_i915_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint32_t flags;
+#define I915_USERPTR_READ_ONLY (1<<0)
+#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
+	uint32_t handle;
+};
+
+static uint32_t userptr_flags;
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static void gem_userptr_test_unsynchronized(void)
+{
+	userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
+}
+
+static void gem_userptr_test_synchronized(void)
+{
+	userptr_flags = 0;
+}
+
+static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	userptr.user_ptr = (uintptr_t)ptr;
+	userptr.user_size = size;
+	userptr.flags = userptr_flags;
+	if (read_only)
+		userptr.flags |= I915_USERPTR_READ_ONLY;
+
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	if (ret)
+		ret = errno;
+	igt_skip_on_f(ret == ENODEV &&
+		      (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) == 0,
+		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
+	if (ret == 0)
+		*handle = userptr.handle;
+
+	return ret;
+}
+
+static uint32_t
+create_userptr(int fd, uint32_t val, uint32_t *ptr)
+{
+	uint32_t handle;
+	int i, ret;
+
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
+	igt_assert(ret == 0);
+	igt_assert(handle != 0);
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		ptr[i] = val++;
+
+	return handle;
+}
+
+static void **handle_ptr_map;
+static unsigned int num_handle_ptr_map;
+
+static void add_handle_ptr(uint32_t handle, void *ptr)
+{
+	if (handle >= num_handle_ptr_map) {
+		handle_ptr_map = realloc(handle_ptr_map,
+					 (handle + 1000) * sizeof(void*));
+		num_handle_ptr_map = handle + 1000;
+	}
+
+	handle_ptr_map[handle] = ptr;
+}
+
+static void *get_handle_ptr(uint32_t handle)
+{
+	return handle_ptr_map[handle];
+}
+
+static void free_handle_ptr(uint32_t handle)
+{
+	igt_assert(handle < num_handle_ptr_map);
+	igt_assert(handle_ptr_map[handle]);
+
+	free(handle_ptr_map[handle]);
+	handle_ptr_map[handle] = NULL;
+}
+
+static uint32_t create_userptr_bo(int fd, int size)
+{
+	void *ptr;
+	uint32_t handle;
+	int ret;
+
+	ret = posix_memalign(&ptr, PAGE_SIZE, size);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
+	igt_assert(ret == 0);
+	add_handle_ptr(handle, ptr);
+
+	return handle;
+}
+
+static void free_userptr_bo(int fd, uint32_t handle)
+{
+	gem_close(fd, handle);
+	free_handle_ptr(handle);
+}
+
+static int has_userptr(int fd)
+{
+	uint32_t handle = 0;
+	void *ptr;
+	uint32_t oldflags;
+	int ret;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+	oldflags = userptr_flags;
+	gem_userptr_test_unsynchronized();
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	userptr_flags = oldflags;
+	if (ret != 0) {
+		free(ptr);
+		return 0;
+	}
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return handle != 0;
+}
+
+static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
+static const unsigned int test_duration_sec = 3;
+
+static volatile unsigned int run_test;
+
+static void alarm_handler(int sig)
+{
+	assert(run_test == 1);
+	run_test = 0;
+}
+
+static void start_test(unsigned int duration)
+{
+	run_test = 1;
+	if (duration == 0)
+		duration = test_duration_sec;
+	signal(SIGALRM, alarm_handler);
+	alarm(duration);
+}
+
+static void exchange_ptr(void *array, unsigned i, unsigned j)
+{
+	void **arr, *tmp;
+	arr = (void **)array;
+
+	tmp = arr[i];
+	arr[i] = arr[j];
+	arr[j] = tmp;
+}
+
+static void test_malloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_malloc_realloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++) {
+			ptr[i] = realloc(ptr[i], 2000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_mmap_unmap(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
+					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+			assert(ptr[i] != MAP_FAILED);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			munmap(ptr[i], 1000);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_ptr_read(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	unsigned long i, loops;
+	register unsigned long v;
+
+	loops = sizeof(linear) / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			v = *p++;
+			v = *p++;
+			v = *p++;
+			v = *p++;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
+}
+
+static void test_ptr_write(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	register unsigned long i, loops;
+
+	loops = sizeof(linear) / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
+}
+
+static void test_impact(int fd)
+{
+	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
+	unsigned int subtest, i;
+	uint32_t handles[nr_bos[total-1]];
+	void *ptr;
+	char buffer[sizeof(linear)];
+
+	for (subtest = 0; subtest < total; subtest++) {
+		for (i = 0; i < nr_bos[subtest]; i++)
+			handles[i] = create_userptr_bo(fd, sizeof(linear));
+
+		if (nr_bos[subtest] > 0)
+			ptr = get_handle_ptr(handles[0]);
+		else
+			ptr = buffer;
+
+		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_read(ptr);
+
+		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_write(ptr);
+
+		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(0);
+		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(1);
+
+		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(0);
+		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(1);
+
+		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(0);
+		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(1);
+
+		for (i = 0; i < nr_bos[subtest]; i++)
+			free_userptr_bo(fd, handles[i]);
+	}
+}
+
+static void test_single(int fd)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handle = 0;
+	unsigned long iter = 0;
+	int ret;
+	unsigned long map_size = sizeof(linear) + PAGE_SIZE - 1;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+					& ~(PAGE_SIZE - 1));
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &handle);
+		assert(ret == 0);
+		gem_close(fd, handle);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_multiple(int fd, unsigned int batch, int random)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handles[10000];
+	int map[10000];
+	unsigned long iter = 0;
+	int ret;
+	int i;
+	unsigned long map_size = batch * sizeof(linear) + PAGE_SIZE - 1;
+
+	assert(batch < (sizeof(handles) / sizeof(handles[0])));
+	assert(batch < (sizeof(map) / sizeof(map[0])));
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+				& ~(PAGE_SIZE - 1));
+
+	for (i = 0; i < batch; i++)
+		map[i] = i;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++) {
+			ret = gem_userptr(fd, bo_ptr + map[i] * sizeof(linear),
+						sizeof(linear),
+						0, &handles[i]);
+			assert(ret == 0);
+		}
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++)
+			gem_close(fd, handles[map[i]]);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter * batch / test_duration_sec);
+}
+
+static void test_userptr(int fd)
+{
+	printf("create-destroy                = ");
+	test_single(fd);
+
+	printf("multi-create-destroy          = ");
+	test_multiple(fd, 100, 0);
+
+	printf("multi-create-destroy-random   = ");
+	test_multiple(fd, 100, 1);
+}
+
+int main(int argc, char **argv)
+{
+	int fd = -1, ret;
+
+	igt_skip_on_simulation();
+
+	igt_subtest_init(argc, argv);
+
+	fd = drm_open_any();
+	igt_assert(fd >= 0);
+
+	ret = has_userptr(fd);
+	igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
+			strerror(errno), ret);
+
+
+	gem_userptr_test_unsynchronized();
+
+	igt_subtest("userptr-unsync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-unsync")
+		test_impact(fd);
+
+	gem_userptr_test_synchronized();
+
+	igt_subtest("userptr-sync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-sync")
+		test_impact(fd);
+
+	igt_exit();
+
+	return 0;
+}
-- 
1.9.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-02-26 16:17 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
@ 2014-03-05 14:48   ` Chris Wilson
  2014-03-12 13:21     ` Tvrtko Ursulin
  0 siblings, 1 reply; 28+ messages in thread
From: Chris Wilson @ 2014-03-05 14:48 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

On Wed, Feb 26, 2014 at 04:17:43PM +0000, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> A set of userptr test cases to support the new feature.
> 
> For the eviction and swapping stress testing I have extracted
> some common behaviour from gem_evict_everything and made both
> test cases use it to avoid duplicating the code.
> 
> Both unsynchronized and synchronized userptr objects are
> tested but the latter set of tests will be skipped if kernel
> is compiled without MMU_NOTIFIERS.
> 
> Also, with 32-bit userspace swapping tests are skipped if
> the system has a lot more RAM than process address space.
> Forking swapping tests are not skipped since they can still
> trigger swapping by cumulative effect.
> 
> v2:
>    * Fixed dmabuf test.
>    * Added test for rejecting read-only.
>    * Fixed ioctl detection for latest kernel patch.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
> +static void
> +copy(int fd, uint32_t dst, uint32_t src, unsigned int error)
> +{
> +	uint32_t batch[10];
> +	struct drm_i915_gem_relocation_entry reloc[2];
> +	struct drm_i915_gem_exec_object2 obj[3];
> +	struct drm_i915_gem_execbuffer2 exec;
> +	uint32_t handle;
> +	int ret;
> +
> +	batch[0] = XY_SRC_COPY_BLT_CMD |
> +		  XY_SRC_COPY_BLT_WRITE_ALPHA |
> +		  XY_SRC_COPY_BLT_WRITE_RGB | 6;

Hmm, you made blit() bdw-aware, but not this copy() routine?

As for the rest, I think we have good coverage.

What I would like to see exercised as well is mmap(fd), shm_open() and
sysv shmem.

Another thing to test is transfering our device fd over a unix socket to
another process and checking that we can continue to access the memory.
(That should just be the same as forking and continuing to use the
parent fd.)

I can think of more wacky vma to use, but I haven't thought of any
corner cases in the code that need exercising.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-03-05 14:48   ` Chris Wilson
@ 2014-03-12 13:21     ` Tvrtko Ursulin
  0 siblings, 0 replies; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-03-12 13:21 UTC (permalink / raw)
  To: Chris Wilson, Intel-gfx, Tvrtko Ursulin



On 03/05/2014 02:48 PM, Chris Wilson wrote:
> On Wed, Feb 26, 2014 at 04:17:43PM +0000, Tvrtko Ursulin wrote:
>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>
>> A set of userptr test cases to support the new feature.
>>
>> For the eviction and swapping stress testing I have extracted
>> some common behaviour from gem_evict_everything and made both
>> test cases use it to avoid duplicating the code.
>>
>> Both unsynchronized and synchronized userptr objects are
>> tested but the latter set of tests will be skipped if kernel
>> is compiled without MMU_NOTIFIERS.
>>
>> Also, with 32-bit userspace swapping tests are skipped if
>> the system has a lot more RAM than process address space.
>> Forking swapping tests are not skipped since they can still
>> trigger swapping by cumulative effect.
>>
>> v2:
>>     * Fixed dmabuf test.
>>     * Added test for rejecting read-only.
>>     * Fixed ioctl detection for latest kernel patch.
>>
>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>> ---
>> +static void
>> +copy(int fd, uint32_t dst, uint32_t src, unsigned int error)
>> +{
>> +	uint32_t batch[10];
>> +	struct drm_i915_gem_relocation_entry reloc[2];
>> +	struct drm_i915_gem_exec_object2 obj[3];
>> +	struct drm_i915_gem_execbuffer2 exec;
>> +	uint32_t handle;
>> +	int ret;
>> +
>> +	batch[0] = XY_SRC_COPY_BLT_CMD |
>> +		  XY_SRC_COPY_BLT_WRITE_ALPHA |
>> +		  XY_SRC_COPY_BLT_WRITE_RGB | 6;
>
> Hmm, you made blit() bdw-aware, but not this copy() routine?

You give me too much credit, it is all c&p from other tests. :)

> As for the rest, I think we have good coverage.
>
> What I would like to see exercised as well is mmap(fd), shm_open() and
> sysv shmem.

What do you mean by mmap(fd), what fd?

And for shared memory flavours - you mean just creating userptr objects 
from them or something more perverse?

> Another thing to test is transfering our device fd over a unix socket to
> another process and checking that we can continue to access the memory.
> (That should just be the same as forking and continuing to use the
> parent fd.)

Not sure I follow - transfer drm fd to a new process and then what?

Regards,

Tvrtko

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 0/3] tests: New userptr test case
  2014-02-26 16:17 [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
                   ` (2 preceding siblings ...)
  2014-02-26 16:17 ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
@ 2014-03-19 11:13 ` Tvrtko Ursulin
  2014-03-19 11:13   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
                     ` (2 more replies)
  2014-04-23 16:38 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
  2014-04-24  9:07 ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
  5 siblings, 3 replies; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-03-19 11:13 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This patch series replaces the old vmap with the new userptr test case
and also adds a benchmark for the new feature.

Tested against version 21 of the kernel patch.

Tvrtko Ursulin (3):
  tests/gem_userptr_blits: Expanded userptr test cases
  tests/gem_vmap_blits: Remove obsolete test case
  tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact

 Android.mk                         |    3 +-
 benchmarks/.gitignore              |    1 +
 benchmarks/Android.mk              |   36 ++
 benchmarks/Makefile.am             |    7 +-
 benchmarks/Makefile.sources        |    6 +
 benchmarks/gem_userptr_benchmark.c |  513 +++++++++++++++
 tests/.gitignore                   |    2 +-
 tests/Makefile.sources             |    2 +-
 tests/gem_userptr_blits.c          | 1244 ++++++++++++++++++++++++++++++++++++
 tests/gem_vmap_blits.c             |  344 ----------
 10 files changed, 1804 insertions(+), 354 deletions(-)
 create mode 100644 benchmarks/Android.mk
 create mode 100644 benchmarks/Makefile.sources
 create mode 100644 benchmarks/gem_userptr_benchmark.c
 create mode 100644 tests/gem_userptr_blits.c
 delete mode 100644 tests/gem_vmap_blits.c

-- 
1.9.0

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-03-19 11:13 ` [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
@ 2014-03-19 11:13   ` Tvrtko Ursulin
  2014-04-18 17:10     ` Volkin, Bradley D
  2014-03-19 11:13   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
  2014-03-19 11:13   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
  2 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-03-19 11:13 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

A set of userptr test cases to support the new feature.

For the eviction and swapping stress testing I have extracted
some common behaviour from gem_evict_everything and made both
test cases use it to avoid duplicating the code.

Both unsynchronized and synchronized userptr objects are
tested but the latter set of tests will be skipped if kernel
is compiled without MMU_NOTIFIERS.

Also, with 32-bit userspace swapping tests are skipped if
the system has a lot more RAM than process address space.
Forking swapping tests are not skipped since they can still
trigger swapping by cumulative effect.

v2:
   * Fixed dmabuf test.
   * Added test for rejecting read-only.
   * Fixed ioctl detection for latest kernel patch.

v3:
   * Updated copy() for Gen8+.
   * Fixed ioctl detection on kernels without MMU_NOTIFIERs.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 tests/.gitignore          |    1 +
 tests/Makefile.sources    |    1 +
 tests/gem_userptr_blits.c | 1244 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1246 insertions(+)
 create mode 100644 tests/gem_userptr_blits.c

diff --git a/tests/.gitignore b/tests/.gitignore
index 623a621..ff1eff5 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -94,6 +94,7 @@ gem_tiling_max_stride
 gem_unfence_active_buffers
 gem_unref_active_buffers
 gem_vmap_blits
+gem_userptr_blits
 gem_wait_render_timeout
 gem_write_read_ring_switch
 gen3_mixed_blits
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 88866ac..240bd99 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -119,6 +119,7 @@ TESTS_progs = \
 	gem_unfence_active_buffers \
 	gem_unref_active_buffers \
 	gem_vmap_blits \
+	gem_userptr_blits \
 	gem_wait_render_timeout \
 	gen3_mixed_blits \
 	gen3_render_linear_blits \
diff --git a/tests/gem_userptr_blits.c b/tests/gem_userptr_blits.c
new file mode 100644
index 0000000..1637297
--- /dev/null
+++ b/tests/gem_userptr_blits.c
@@ -0,0 +1,1244 @@
+/*
+ * Copyright © 2009-2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Chris Wilson <chris@chris-wilson.co.uk>
+ *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+ *
+ */
+
+/** @file gem_userptr_blits.c
+ *
+ * This is a test of doing many blits using a mixture of normal system pages
+ * and uncached linear buffers, with a working set larger than the
+ * aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+#include "eviction_common.c"
+
+#define WIDTH 512
+#define HEIGHT 512
+#define PAGE_SIZE 4096
+
+#define LOCAL_I915_GEM_USERPTR       0x34
+#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
+struct local_i915_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint32_t flags;
+#define I915_USERPTR_READ_ONLY (1<<0)
+#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
+	uint32_t handle;
+};
+
+static uint32_t userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static void gem_userptr_test_unsynchronized(void)
+{
+	userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
+}
+
+static void gem_userptr_test_synchronized(void)
+{
+	userptr_flags = 0;
+}
+
+static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	userptr.user_ptr = (uintptr_t)ptr;
+	userptr.user_size = size;
+	userptr.flags = userptr_flags;
+	if (read_only)
+		userptr.flags |= I915_USERPTR_READ_ONLY;
+
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	if (ret)
+		ret = errno;
+	igt_skip_on_f(ret == ENODEV &&
+		      (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) == 0 &&
+		      !read_only,
+		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
+	if (ret == 0)
+		*handle = userptr.handle;
+
+	return ret;
+}
+
+
+static void gem_userptr_sync(int fd, uint32_t handle)
+{
+	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+}
+
+static void
+copy(int fd, uint32_t dst, uint32_t src, unsigned int error)
+{
+	uint32_t batch[12];
+	struct drm_i915_gem_relocation_entry reloc[2];
+	struct drm_i915_gem_exec_object2 obj[3];
+	struct drm_i915_gem_execbuffer2 exec;
+	uint32_t handle;
+	int ret, i=0;
+
+	batch[i++] = XY_SRC_COPY_BLT_CMD |
+		  XY_SRC_COPY_BLT_WRITE_ALPHA |
+		  XY_SRC_COPY_BLT_WRITE_RGB;
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i - 1] |= 8;
+	else
+		batch[i - 1] |= 6;
+
+	batch[i++] = (3 << 24) | /* 32 bits */
+		  (0xcc << 16) | /* copy ROP */
+		  WIDTH*4;
+	batch[i++] = 0; /* dst x1,y1 */
+	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+	batch[i++] = 0; /* dst reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = 0; /* src x1,y1 */
+	batch[i++] = WIDTH*4;
+	batch[i++] = 0; /* src reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = MI_BATCH_BUFFER_END;
+	batch[i++] = MI_NOOP;
+
+	handle = gem_create(fd, 4096);
+	gem_write(fd, handle, 0, batch, sizeof(batch));
+
+	reloc[0].target_handle = dst;
+	reloc[0].delta = 0;
+	reloc[0].offset = 4 * sizeof(batch[0]);
+	reloc[0].presumed_offset = 0;
+	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
+	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+	reloc[1].target_handle = src;
+	reloc[1].delta = 0;
+	reloc[1].offset = 7 * sizeof(batch[0]);
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		reloc[1].offset += sizeof(batch[0]);
+	reloc[1].presumed_offset = 0;
+	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
+	reloc[1].write_domain = 0;
+
+	obj[0].handle = dst;
+	obj[0].relocation_count = 0;
+	obj[0].relocs_ptr = 0;
+	obj[0].alignment = 0;
+	obj[0].offset = 0;
+	obj[0].flags = 0;
+	obj[0].rsvd1 = 0;
+	obj[0].rsvd2 = 0;
+
+	obj[1].handle = src;
+	obj[1].relocation_count = 0;
+	obj[1].relocs_ptr = 0;
+	obj[1].alignment = 0;
+	obj[1].offset = 0;
+	obj[1].flags = 0;
+	obj[1].rsvd1 = 0;
+	obj[1].rsvd2 = 0;
+
+	obj[2].handle = handle;
+	obj[2].relocation_count = 2;
+	obj[2].relocs_ptr = (uintptr_t)reloc;
+	obj[2].alignment = 0;
+	obj[2].offset = 0;
+	obj[2].flags = 0;
+	obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+	exec.buffers_ptr = (uintptr_t)obj;
+	exec.buffer_count = 3;
+	exec.batch_start_offset = 0;
+	exec.batch_len = i * 4;
+	exec.DR1 = exec.DR4 = 0;
+	exec.num_cliprects = 0;
+	exec.cliprects_ptr = 0;
+	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+	i915_execbuffer2_set_context_id(exec, 0);
+	exec.rsvd2 = 0;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+	if (ret)
+		ret = errno;
+
+	if (error == ~0)
+		igt_assert(ret != 0);
+	else
+		igt_assert(ret == error);
+
+	gem_close(fd, handle);
+}
+
+static void
+blit(int fd, uint32_t dst, uint32_t src, uint32_t *all_bo, int n_bo, int error)
+{
+	uint32_t batch[12];
+	struct drm_i915_gem_relocation_entry reloc[2];
+	struct drm_i915_gem_exec_object2 *obj;
+	struct drm_i915_gem_execbuffer2 exec;
+	uint32_t handle;
+	int n, ret, i=0;
+
+	batch[i++] = XY_SRC_COPY_BLT_CMD |
+		  XY_SRC_COPY_BLT_WRITE_ALPHA |
+		  XY_SRC_COPY_BLT_WRITE_RGB;
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i - 1] |= 8;
+	else
+		batch[i - 1] |= 6;
+	batch[i++] = (3 << 24) | /* 32 bits */
+		  (0xcc << 16) | /* copy ROP */
+		  WIDTH*4;
+	batch[i++] = 0; /* dst x1,y1 */
+	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+	batch[i++] = 0; /* dst reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = 0; /* src x1,y1 */
+	batch[i++] = WIDTH*4;
+	batch[i++] = 0; /* src reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = MI_BATCH_BUFFER_END;
+	batch[i++] = MI_NOOP;
+
+	handle = gem_create(fd, 4096);
+	gem_write(fd, handle, 0, batch, sizeof(batch));
+
+	reloc[0].target_handle = dst;
+	reloc[0].delta = 0;
+	reloc[0].offset = 4 * sizeof(batch[0]);
+	reloc[0].presumed_offset = 0;
+	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+	reloc[1].target_handle = src;
+	reloc[1].delta = 0;
+	reloc[1].offset = 7 * sizeof(batch[0]);
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		reloc[1].offset += sizeof(batch[0]);
+	reloc[1].presumed_offset = 0;
+	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc[1].write_domain = 0;
+
+	obj = calloc(n_bo + 1, sizeof(*obj));
+	for (n = 0; n < n_bo; n++)
+		obj[n].handle = all_bo[n];
+	obj[n].handle = handle;
+	obj[n].relocation_count = 2;
+	obj[n].relocs_ptr = (uintptr_t)reloc;
+
+	exec.buffers_ptr = (uintptr_t)obj;
+	exec.buffer_count = n_bo + 1;
+	exec.batch_start_offset = 0;
+	exec.batch_len = i * 4;
+	exec.DR1 = exec.DR4 = 0;
+	exec.num_cliprects = 0;
+	exec.cliprects_ptr = 0;
+	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+	i915_execbuffer2_set_context_id(exec, 0);
+	exec.rsvd2 = 0;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+	if (ret)
+		ret = errno;
+
+	igt_assert(ret == error);
+
+	gem_close(fd, handle);
+	free(obj);
+}
+
+static uint32_t
+create_userptr(int fd, uint32_t val, uint32_t *ptr)
+{
+	uint32_t handle;
+	int i, ret;
+
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
+	igt_assert(ret == 0);
+	igt_assert(handle != 0);
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		ptr[i] = val++;
+
+	return handle;
+}
+
+static void **handle_ptr_map;
+static unsigned int num_handle_ptr_map;
+
+static void add_handle_ptr(uint32_t handle, void *ptr)
+{
+	if (handle >= num_handle_ptr_map) {
+		handle_ptr_map = realloc(handle_ptr_map,
+					 (handle + 1000) * sizeof(void*));
+		num_handle_ptr_map = handle + 1000;
+	}
+
+	handle_ptr_map[handle] = ptr;
+}
+
+static void *get_handle_ptr(uint32_t handle)
+{
+	return handle_ptr_map[handle];
+}
+
+static void free_handle_ptr(uint32_t handle)
+{
+	igt_assert(handle < num_handle_ptr_map);
+	igt_assert(handle_ptr_map[handle]);
+
+	free(handle_ptr_map[handle]);
+	handle_ptr_map[handle] = NULL;
+}
+
+static uint32_t create_userptr_bo(int fd, int size)
+{
+	void *ptr;
+	uint32_t handle;
+	int ret;
+
+	ret = posix_memalign(&ptr, PAGE_SIZE, size);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
+	igt_assert(ret == 0);
+	add_handle_ptr(handle, ptr);
+
+	return handle;
+}
+
+static void clear(int fd, uint32_t handle, int size)
+{
+	void *ptr = get_handle_ptr(handle);
+
+	igt_assert(ptr != NULL);
+
+	memset(ptr, 0, size);
+}
+
+static void free_userptr_bo(int fd, uint32_t handle)
+{
+	gem_close(fd, handle);
+	free_handle_ptr(handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+	uint32_t handle;
+	int i;
+
+	handle = gem_create(fd, sizeof(linear));
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		linear[i] = val++;
+	gem_write(fd, handle, 0, linear, sizeof(linear));
+
+	return handle;
+}
+
+static void
+check_cpu(uint32_t *ptr, uint32_t val)
+{
+	int i;
+
+	for (i = 0; i < WIDTH*HEIGHT; i++) {
+		if (ptr[i] != val) {
+			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+				"at offset 0x%08x\n",
+				val, ptr[i], i * 4);
+			abort();
+		}
+		val++;
+	}
+}
+
+static void
+check_gpu(int fd, uint32_t handle, uint32_t val)
+{
+	gem_read(fd, handle, 0, linear, sizeof(linear));
+	check_cpu(linear, val);
+}
+
+static int has_userptr(int fd)
+{
+	uint32_t handle = 0;
+	void *ptr;
+	uint32_t oldflags;
+	int ret;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+	oldflags = userptr_flags;
+	gem_userptr_test_unsynchronized();
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	userptr_flags = oldflags;
+	if (ret != 0) {
+		free(ptr);
+		return 0;
+	}
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return handle != 0;
+}
+
+static int test_input_checking(int fd)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	/* Invalid flags. */
+	userptr.user_ptr = 0;
+	userptr.user_size = 0;
+	userptr.flags = ~0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	/* Too big. */
+	userptr.user_ptr = 0;
+	userptr.user_size = ~0;
+	userptr.flags = 0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	/* Both wrong. */
+	userptr.user_ptr = 0;
+	userptr.user_size = ~0;
+	userptr.flags = ~0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	return 0;
+}
+
+static int test_access_control(int fd)
+{
+	igt_fork(child, 1) {
+		void *ptr;
+		int ret;
+		uint32_t handle;
+
+		igt_drop_root();
+
+		/* CAP_SYS_ADMIN is needed for UNSYNCHRONIZED mappings. */
+		gem_userptr_test_unsynchronized();
+
+		igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+		ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+		if (ret == 0)
+			gem_close(fd, handle);
+		free(ptr);
+		igt_assert(ret == EPERM);
+	}
+
+	igt_waitchildren();
+
+	return 0;
+}
+
+static int test_invalid_mapping(int fd)
+{
+	int ret;
+	uint32_t handle, handle2;
+	void *ptr;
+
+	/* NULL pointer. */
+	ret = gem_userptr(fd, NULL, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
+	gem_close(fd, handle);
+
+	/* GTT mapping */
+	handle = create_bo(fd, 0);
+	ptr = gem_mmap__gtt(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
+	if (ptr == NULL)
+		gem_close(fd, handle);
+	assert(ptr != NULL);
+	assert(((unsigned long)ptr & (PAGE_SIZE - 1)) == 0);
+	assert((sizeof(linear) & (PAGE_SIZE - 1)) == 0);
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle2);
+	igt_assert(ret == 0);
+	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
+	gem_close(fd, handle2);
+	munmap(ptr, sizeof(linear));
+	gem_close(fd, handle);
+
+	return 0;
+}
+
+static int test_forbidden_ops(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+	char buf[PAGE_SIZE];
+	struct drm_i915_gem_pread gem_pread;
+	struct drm_i915_gem_pwrite gem_pwrite;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	gem_pread.handle = handle;
+	gem_pread.offset = 0;
+	gem_pread.size = PAGE_SIZE;
+	gem_pread.data_ptr = (uintptr_t)buf;
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
+	if (ret == 0) {
+		gem_close(fd, handle);
+		free(ptr);
+	}
+	igt_assert(ret != 0);
+
+	gem_pwrite.handle = handle;
+	gem_pwrite.offset = 0;
+	gem_pwrite.size = PAGE_SIZE;
+	gem_pwrite.data_ptr = (uintptr_t)buf;
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
+	if (ret == 0) {
+		gem_close(fd, handle);
+		free(ptr);
+	}
+	igt_assert(ret != 0);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static char counter;
+
+static void (*orig_sigbus)(int sig, siginfo_t *info, void *param);
+static unsigned long sigbus_start;
+static long sigbus_cnt = -1;
+
+static void
+check_bo(int fd1, uint32_t handle1, int is_userptr, int fd2, uint32_t handle2)
+{
+	char *ptr1, *ptr2;
+	int i;
+	unsigned long size = sizeof(linear);
+
+	if (is_userptr)
+		ptr1 = get_handle_ptr(handle1);
+	else
+		ptr1 = gem_mmap(fd1, handle1, sizeof(linear), PROT_READ | PROT_WRITE);
+
+	ptr2 = gem_mmap(fd2, handle2, sizeof(linear), PROT_READ | PROT_WRITE);
+
+	igt_assert(ptr1);
+	igt_assert(ptr2);
+
+	sigbus_start = (unsigned long)ptr2;
+
+	if (sigbus_cnt == 0)
+		size = 1;
+
+	/* check whether it's still our old object first. */
+	for (i = 0; i < size; i++) {
+		igt_assert(ptr1[i] == counter);
+		igt_assert(ptr2[i] == counter);
+	}
+
+	counter++;
+
+	if (size > 1) {
+		memset(ptr1, counter, size);
+		igt_assert(memcmp(ptr1, ptr2, size) == 0);
+	}
+
+	if (!is_userptr)
+		munmap(ptr1, sizeof(linear));
+	munmap(ptr2, sizeof(linear));
+}
+
+static int export_handle(int fd, uint32_t handle, int *outfd)
+{
+	struct drm_prime_handle args;
+	int ret;
+
+	args.handle = handle;
+	args.flags = DRM_CLOEXEC;
+	args.fd = -1;
+
+	ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
+	if (ret)
+		ret = errno;
+	*outfd = args.fd;
+
+	return ret;
+}
+
+static void sigbus(int sig, siginfo_t *info, void *param)
+{
+	unsigned long ptr = (unsigned long)info->si_addr;
+	void *addr;
+
+	if (ptr >= sigbus_start &&
+	    ptr <= (sigbus_start + sizeof(linear))) {
+		sigbus_cnt++;
+		addr = mmap((void *)ptr, sizeof(linear), PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
+		if ((unsigned long)addr == ptr) {
+			memset(addr, counter, sizeof(linear));
+			return;
+		}
+	}
+
+	if (orig_sigbus)
+		orig_sigbus(sig, info, param);
+	assert(0);
+}
+
+static int test_dmabuf(void)
+{
+	int fd1, fd2;
+	uint32_t handle, handle_import1, handle_import2, handle_selfimport;
+	int dma_buf_fd = -1;
+	int ret;
+	struct sigaction sigact, orig_sigact;
+
+	fd1 = drm_open_any();
+	fd2 = drm_open_any();
+
+	handle = create_userptr_bo(fd1, sizeof(linear));
+
+	ret = export_handle(fd1, handle, &dma_buf_fd);
+	if (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) {
+		igt_assert(ret == EINVAL);
+		free_userptr_bo(fd1, handle);
+
+		return 0;
+	} else {
+		igt_assert(ret == 0);
+		igt_assert(dma_buf_fd >= 0);
+	}
+	handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd);
+	check_bo(fd1, handle, 1, fd2, handle_import1);
+
+	/* reimport should give us the same handle so that userspace can check
+	 * whether it has that bo already somewhere. */
+	handle_import2 = prime_fd_to_handle(fd2, dma_buf_fd);
+	igt_assert(handle_import1 == handle_import2);
+
+	/* Same for re-importing on the exporting fd. */
+	handle_selfimport = prime_fd_to_handle(fd1, dma_buf_fd);
+	igt_assert(handle == handle_selfimport);
+
+	/* close dma_buf, check whether nothing disappears. */
+	close(dma_buf_fd);
+	check_bo(fd1, handle, 1, fd2, handle_import1);
+
+	/* destroy userptr object and expect SIGBUS */
+	free_userptr_bo(fd1, handle);
+	sigact.sa_sigaction = sigbus;
+	sigact.sa_flags = SA_SIGINFO;
+	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
+	assert(ret == 0);
+	orig_sigbus = orig_sigact.sa_sigaction;
+	sigbus_cnt = 0;
+	check_bo(fd2, handle_import1, 0, fd2, handle_import1);
+	assert(sigbus_cnt > 0);
+	sigact.sa_sigaction = orig_sigbus;
+	sigact.sa_flags = SA_SIGINFO;
+	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
+	assert(ret == 0);
+
+	gem_close(fd2, handle_import1);
+	close(fd1);
+	close(fd2);
+
+	return 0;
+}
+
+static int test_usage_restrictions(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE * 2) == 0);
+
+	/* Address not aligned. */
+	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Size not rounded to page size. */
+	ret = gem_userptr(fd, ptr, PAGE_SIZE - 1, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Both wrong. */
+	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE - 1, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Read-only not supported. */
+	ret = gem_userptr(fd, (char *)ptr, PAGE_SIZE, 1, &handle);
+	igt_assert(ret != 0);
+
+	free(ptr);
+
+	return 0;
+}
+
+static int test_create_destroy(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+
+	igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static int test_coherency(int fd, int count)
+{
+	uint32_t *memory;
+	uint32_t *cpu, *cpu_val;
+	uint32_t *gpu, *gpu_val;
+	uint32_t start = 0;
+	int i, ret;
+
+	printf("Using 2x%d 1MiB buffers\n", count);
+
+	ret = posix_memalign((void **)&memory, PAGE_SIZE, count*sizeof(linear));
+	if (ret != 0 || memory == NULL) {
+		fprintf(stderr, "Unable to allocate %lld bytes\n",
+			(long long)count*sizeof(linear));
+		return 1;
+	}
+
+	gpu = malloc(sizeof(uint32_t)*count*4);
+	gpu_val = gpu + count;
+	cpu = gpu_val + count;
+	cpu_val = cpu + count;
+
+	for (i = 0; i < count; i++) {
+		gpu[i] = create_bo(fd, start);
+		gpu_val[i] = start;
+		start += WIDTH*HEIGHT;
+	}
+
+	for (i = 0; i < count; i++) {
+		cpu[i] = create_userptr(fd, start, memory+i*WIDTH*HEIGHT);
+		cpu_val[i] = start;
+		start += WIDTH*HEIGHT;
+	}
+
+	printf("Verifying initialisation...\n");
+	for (i = 0; i < count; i++) {
+		check_gpu(fd, gpu[i], gpu_val[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+	}
+
+	printf("Cyclic blits cpu->gpu, forward...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = i % count;
+		int dst = (i + 1) % count;
+
+		copy(fd, gpu[dst], cpu[src], 0);
+		gpu_val[dst] = cpu_val[src];
+	}
+	for (i = 0; i < count; i++)
+		check_gpu(fd, gpu[i], gpu_val[i]);
+
+	printf("Cyclic blits gpu->cpu, backward...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = (i + 1) % count;
+		int dst = i % count;
+
+		copy(fd, cpu[dst], gpu[src], 0);
+		cpu_val[dst] = gpu_val[src];
+	}
+	for (i = 0; i < count; i++) {
+		gem_userptr_sync(fd, cpu[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+	}
+
+	printf("Random blits...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = random() % count;
+		int dst = random() % count;
+
+		if (random() & 1) {
+			copy(fd, gpu[dst], cpu[src], 0);
+			gpu_val[dst] = cpu_val[src];
+		} else {
+			copy(fd, cpu[dst], gpu[src], 0);
+			cpu_val[dst] = gpu_val[src];
+		}
+	}
+	for (i = 0; i < count; i++) {
+		check_gpu(fd, gpu[i], gpu_val[i]);
+		gem_close(fd, gpu[i]);
+
+		gem_userptr_sync(fd, cpu[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+		gem_close(fd, cpu[i]);
+	}
+
+	free(gpu);
+	free(memory);
+
+	return 0;
+}
+
+static struct igt_eviction_test_ops fault_ops = {
+	.create = create_userptr_bo,
+	.close = free_userptr_bo,
+	.copy = blit,
+	.clear = clear,
+};
+
+static int can_swap(void)
+{
+	unsigned long as, ram;
+
+	/* Cannot swap if not enough address space */
+
+	/* FIXME: Improve check criteria. */
+	if (sizeof(void*) < 8)
+		as = 3 * 1024;
+	else
+		as = 256 * 1024; /* Just a big number */
+
+	ram = intel_get_total_ram_mb();
+
+	if ((as - 128) < (ram - 256))
+		return 0;
+
+	return 1;
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static void test_forking_evictions(int fd, int size, int count,
+			     unsigned flags)
+{
+	int trash_count;
+	int num_threads;
+
+	trash_count = intel_get_total_ram_mb() * 11 / 10;
+	/* Use the fact test will spawn a number of child
+	 * processes meaning swapping will be triggered system
+	 * wide even if one process on it's own can't do it.
+	 */
+	num_threads = min(sysconf(_SC_NPROCESSORS_ONLN) * 4, 12);
+	trash_count /= num_threads;
+	if (count > trash_count)
+		count = trash_count;
+
+	forking_evictions(fd, &fault_ops, size, count, trash_count, flags);
+}
+
+static void test_swapping_evictions(int fd, int size, int count)
+{
+	int trash_count;
+
+	igt_skip_on_f(!can_swap(),
+		"Not enough process address space for swapping tests.\n");
+
+	trash_count = intel_get_total_ram_mb() * 11 / 10;
+
+	swapping_evictions(fd, &fault_ops, size, count, trash_count);
+}
+
+static void test_minor_evictions(int fd, int size, int count)
+{
+	minor_evictions(fd, &fault_ops, size, count);
+}
+
+static void test_major_evictions(int fd, int size, int count)
+{
+	major_evictions(fd, &fault_ops, size, count);
+}
+
+static int test_overlap(int fd, int expected)
+{
+	char *ptr;
+	int ret;
+	uint32_t handle, handle2;
+
+	igt_assert(posix_memalign((void *)&ptr, PAGE_SIZE, PAGE_SIZE * 3) == 0);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle2);
+	igt_assert(ret == 0);
+	gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE * 2, PAGE_SIZE, 0, &handle2);
+	igt_assert(ret == 0);
+	gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE * 2, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE * 2, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE * 3, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static int test_unmap(int fd, int expected)
+{
+	char *ptr, *bo_ptr;
+	const unsigned int num_obj = 3;
+	unsigned int i;
+	uint32_t bo[num_obj + 1];
+	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
+	int ret;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+						& ~(PAGE_SIZE - 1));
+
+	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
+		igt_assert(ret == 0);
+	}
+
+	bo[num_obj] = create_bo(fd, 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], 0);
+
+	ret = munmap(ptr, map_size);
+	assert(ret == 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], expected);
+
+	for (i = 0; i < (num_obj + 1); i++)
+		gem_close(fd, bo[i]);
+
+	return 0;
+}
+
+static int test_unmap_after_close(int fd)
+{
+	char *ptr, *bo_ptr;
+	const unsigned int num_obj = 3;
+	unsigned int i;
+	uint32_t bo[num_obj + 1];
+	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
+	int ret;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+						& ~(PAGE_SIZE - 1));
+
+	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
+		igt_assert(ret == 0);
+	}
+
+	bo[num_obj] = create_bo(fd, 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], 0);
+
+	for (i = 0; i < (num_obj + 1); i++)
+		gem_close(fd, bo[i]);
+
+	ret = munmap(ptr, map_size);
+	assert(ret == 0);
+
+	return 0;
+}
+
+static int test_unmap_cycles(int fd, int expected)
+{
+	int i;
+
+	for (i = 0; i < 1000; i++)
+		test_unmap(fd, expected);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	uint64_t aperture_size;
+	unsigned int total_ram;
+	int fd = -1, count = 0, size = 0, ret;
+
+	igt_skip_on_simulation();
+
+	igt_subtest_init(argc, argv);
+
+	igt_fixture {
+		fd = drm_open_any();
+		igt_assert(fd >= 0);
+
+		ret = has_userptr(fd);
+		igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
+			      strerror(errno), ret);
+
+		size = sizeof(linear);
+
+		aperture_size = gem_aperture_size(fd);
+		printf("Aperture size is %lu MiB\n", (long)(aperture_size / (1024*1024)));
+
+		if (argc > 1)
+			count = atoi(argv[1]);
+		if (count == 0)
+			count = 2 * aperture_size / (1024*1024) / 3;
+
+		total_ram = intel_get_total_ram_mb();
+		printf("Total RAM is %u MiB\n", total_ram);
+
+		if (count > total_ram * 3 / 4) {
+			count = intel_get_total_ram_mb() * 3 / 4;
+			printf("Not enough RAM to run test, reducing buffer count.\n");
+		}
+	}
+
+	igt_subtest("input-checking")
+		test_input_checking(fd);
+
+	igt_subtest("usage-restrictions")
+		test_usage_restrictions(fd);
+
+	igt_subtest("invalid-mapping")
+		test_invalid_mapping(fd);
+
+	igt_subtest("forbidden-operations")
+		test_forbidden_ops(fd);
+
+	printf("Testing unsynchronized mappings...\n");
+	gem_userptr_test_unsynchronized();
+
+	igt_subtest("create-destroy-unsync")
+		test_create_destroy(fd);
+
+	igt_subtest("unsync-overlap")
+		test_overlap(fd, 0);
+
+	igt_subtest("unsync-unmap")
+		test_unmap(fd, 0);
+
+	igt_subtest("unsync-unmap-cycles")
+		test_unmap_cycles(fd, 0);
+
+	igt_subtest("unsync-unmap-after-close")
+		test_unmap_after_close(fd);
+
+	igt_subtest("coherency-unsync")
+		test_coherency(fd, count);
+
+	igt_subtest("dmabuf-unsync")
+		test_dmabuf();
+
+	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
+		igt_subtest_f("forked-unsync%s%s%s-%s",
+		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
+		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
+		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
+				"-mempressure" : "",
+		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
+				"interruptible" : "normal") {
+			test_forking_evictions(fd, size, count, flags);
+		}
+	}
+
+	igt_subtest("swapping-unsync-normal")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-unsync-normal")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-unsync-normal") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_fixture {
+		size = sizeof(linear);
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	igt_fork_signal_helper();
+
+	igt_subtest("swapping-unsync-interruptible")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-unsync-interruptible")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-unsync-interruptible") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_stop_signal_helper();
+
+	printf("Testing synchronized mappings...\n");
+
+	igt_fixture {
+		size = sizeof(linear);
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	gem_userptr_test_synchronized();
+
+	igt_subtest("create-destroy-sync")
+		test_create_destroy(fd);
+
+	igt_subtest("sync-overlap")
+		test_overlap(fd, EINVAL);
+
+	igt_subtest("sync-unmap")
+		test_unmap(fd, EFAULT);
+
+	igt_subtest("sync-unmap-cycles")
+		test_unmap_cycles(fd, EFAULT);
+
+	igt_subtest("sync-unmap-after-close")
+		test_unmap_after_close(fd);
+
+	igt_subtest("coherency-sync")
+		test_coherency(fd, count);
+
+	igt_subtest("dmabuf-sync")
+		test_dmabuf();
+
+	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
+		igt_subtest_f("forked-sync%s%s%s-%s",
+		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
+		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
+		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
+				"-mempressure" : "",
+		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
+				"interruptible" : "normal") {
+			test_forking_evictions(fd, size, count, flags);
+		}
+	}
+
+	igt_subtest("swapping-normal-sync")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-normal-sync")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-normal-sync") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_fixture {
+		size = 1024 * 1024;
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	igt_fork_signal_helper();
+
+	igt_subtest("swapping-sync-interruptible")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-sync-interruptible")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-sync-interruptible") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_stop_signal_helper();
+
+	igt_subtest("access-control")
+	test_access_control(fd);
+
+	igt_exit();
+
+	return 0;
+}
-- 
1.9.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case
  2014-03-19 11:13 ` [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
  2014-03-19 11:13   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
@ 2014-03-19 11:13   ` Tvrtko Ursulin
  2014-04-17 23:20     ` Volkin, Bradley D
  2014-03-19 11:13   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
  2 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-03-19 11:13 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

No need for the old test case once the new one was added.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 tests/.gitignore       |   1 -
 tests/Makefile.sources |   1 -
 tests/gem_vmap_blits.c | 344 -------------------------------------------------
 3 files changed, 346 deletions(-)
 delete mode 100644 tests/gem_vmap_blits.c

diff --git a/tests/.gitignore b/tests/.gitignore
index ff1eff5..c600823 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -93,7 +93,6 @@ gem_tiled_swapping
 gem_tiling_max_stride
 gem_unfence_active_buffers
 gem_unref_active_buffers
-gem_vmap_blits
 gem_userptr_blits
 gem_wait_render_timeout
 gem_write_read_ring_switch
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 240bd99..610bbf5 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -118,7 +118,6 @@ TESTS_progs = \
 	gem_tiling_max_stride \
 	gem_unfence_active_buffers \
 	gem_unref_active_buffers \
-	gem_vmap_blits \
 	gem_userptr_blits \
 	gem_wait_render_timeout \
 	gen3_mixed_blits \
diff --git a/tests/gem_vmap_blits.c b/tests/gem_vmap_blits.c
deleted file mode 100644
index 48297af..0000000
--- a/tests/gem_vmap_blits.c
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright © 2009,2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *    Chris Wilson <chris@chris-wilson.co.uk>
- *
- */
-
-/** @file gem_vmap_blits.c
- *
- * This is a test of doing many blits using a mixture of normal system pages
- * and uncached linear buffers, with a working set larger than the
- * aperture size.
- *
- * The goal is to simply ensure the basics work.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include "drm.h"
-#include "i915_drm.h"
-#include "drmtest.h"
-#include "intel_bufmgr.h"
-#include "intel_batchbuffer.h"
-#include "intel_gpu_tools.h"
-
-#if !defined(I915_PARAM_HAS_VMAP)
-#pragma message("No vmap support in drm, skipping")
-int main(int argc, char **argv)
-{
-	fprintf(stderr, "No vmap support in drm.\n");
-	return 77;
-}
-#else
-
-#define WIDTH 512
-#define HEIGHT 512
-
-static uint32_t linear[WIDTH*HEIGHT];
-
-static uint32_t gem_vmap(int fd, void *ptr, int size, int read_only)
-{
-	struct drm_i915_gem_vmap vmap;
-
-	vmap.user_ptr = (uintptr_t)ptr;
-	vmap.user_size = size;
-	vmap.flags = 0;
-	if (read_only)
-		vmap.flags |= I915_VMAP_READ_ONLY;
-
-	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_VMAP, &vmap))
-		return 0;
-
-	return vmap.handle;
-}
-
-
-static void gem_vmap_sync(int fd, uint32_t handle)
-{
-	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
-}
-
-static void
-copy(int fd, uint32_t dst, uint32_t src)
-{
-	uint32_t batch[10];
-	struct drm_i915_gem_relocation_entry reloc[2];
-	struct drm_i915_gem_exec_object2 obj[3];
-	struct drm_i915_gem_execbuffer2 exec;
-	uint32_t handle;
-	int ret;
-
-	batch[0] = XY_SRC_COPY_BLT_CMD |
-		  XY_SRC_COPY_BLT_WRITE_ALPHA |
-		  XY_SRC_COPY_BLT_WRITE_RGB | 6;
-	batch[1] = (3 << 24) | /* 32 bits */
-		  (0xcc << 16) | /* copy ROP */
-		  WIDTH*4;
-	batch[2] = 0; /* dst x1,y1 */
-	batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
-	batch[4] = 0; /* dst reloc */
-	batch[5] = 0; /* src x1,y1 */
-	batch[6] = WIDTH*4;
-	batch[7] = 0; /* src reloc */
-	batch[8] = MI_BATCH_BUFFER_END;
-	batch[9] = MI_NOOP;
-
-	handle = gem_create(fd, 4096);
-	gem_write(fd, handle, 0, batch, sizeof(batch));
-
-	reloc[0].target_handle = dst;
-	reloc[0].delta = 0;
-	reloc[0].offset = 4 * sizeof(batch[0]);
-	reloc[0].presumed_offset = 0;
-	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
-	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
-
-	reloc[1].target_handle = src;
-	reloc[1].delta = 0;
-	reloc[1].offset = 7 * sizeof(batch[0]);
-	reloc[1].presumed_offset = 0;
-	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
-	reloc[1].write_domain = 0;
-
-	obj[0].handle = dst;
-	obj[0].relocation_count = 0;
-	obj[0].relocs_ptr = 0;
-	obj[0].alignment = 0;
-	obj[0].offset = 0;
-	obj[0].flags = 0;
-	obj[0].rsvd1 = 0;
-	obj[0].rsvd2 = 0;
-
-	obj[1].handle = src;
-	obj[1].relocation_count = 0;
-	obj[1].relocs_ptr = 0;
-	obj[1].alignment = 0;
-	obj[1].offset = 0;
-	obj[1].flags = 0;
-	obj[1].rsvd1 = 0;
-	obj[1].rsvd2 = 0;
-
-	obj[2].handle = handle;
-	obj[2].relocation_count = 2;
-	obj[2].relocs_ptr = (uintptr_t)reloc;
-	obj[2].alignment = 0;
-	obj[2].offset = 0;
-	obj[2].flags = 0;
-	obj[2].rsvd1 = obj[2].rsvd2 = 0;
-
-	exec.buffers_ptr = (uintptr_t)obj;
-	exec.buffer_count = 3;
-	exec.batch_start_offset = 0;
-	exec.batch_len = sizeof(batch);
-	exec.DR1 = exec.DR4 = 0;
-	exec.num_cliprects = 0;
-	exec.cliprects_ptr = 0;
-	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
-	exec.rsvd1 = exec.rsvd2 = 0;
-
-	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
-	while (ret && errno == EBUSY) {
-		drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
-		ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
-	}
-	igt_assert(ret == 0);
-
-	gem_close(fd, handle);
-}
-
-static uint32_t
-create_vmap(int fd, uint32_t val, uint32_t *ptr)
-{
-	uint32_t handle;
-	int i;
-
-	handle = gem_vmap(fd, ptr, sizeof(linear), 0);
-
-	/* Fill the BO with dwords starting at val */
-	for (i = 0; i < WIDTH*HEIGHT; i++)
-		ptr[i] = val++;
-
-	return handle;
-}
-
-static uint32_t
-create_bo(int fd, uint32_t val)
-{
-	uint32_t handle;
-	int i;
-
-	handle = gem_create(fd, sizeof(linear));
-
-	/* Fill the BO with dwords starting at val */
-	for (i = 0; i < WIDTH*HEIGHT; i++)
-		linear[i] = val++;
-	gem_write(fd, handle, 0, linear, sizeof(linear));
-
-	return handle;
-}
-
-static void
-check_cpu(uint32_t *ptr, uint32_t val)
-{
-	int i;
-
-	for (i = 0; i < WIDTH*HEIGHT; i++) {
-		if (ptr[i] != val) {
-			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
-				"at offset 0x%08x\n",
-				val, ptr[i], i * 4);
-			abort();
-		}
-		val++;
-	}
-}
-
-static void
-check_gpu(int fd, uint32_t handle, uint32_t val)
-{
-	gem_read(fd, handle, 0, linear, sizeof(linear));
-	check_cpu(linear, val);
-}
-
-static int has_vmap(int fd)
-{
-	drm_i915_getparam_t gp;
-	int i;
-
-	gp.param = I915_PARAM_HAS_VMAP;
-	gp.value = &i;
-
-	return drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0 && i > 0;
-}
-
-int main(int argc, char **argv)
-{
-	uint32_t *memory;
-	uint32_t *cpu, *cpu_val;
-	uint32_t *gpu, *gpu_val;
-	uint32_t start = 0;
-	int i, fd, count;
-
-	igt_simple_init();
-
-	igt_skip_on_simulation();
-
-	fd = drm_open_any();
-
-	if (!has_vmap(fd)) {
-		fprintf(stderr, "No vmap support, ignoring.\n");
-		return 77;
-	}
-
-	count = 0;
-	if (argc > 1)
-		count = atoi(argv[1]);
-	if (count == 0)
-		count = 3 * gem_aperture_size(fd) / (1024*1024) / 4;
-	printf("Using 2x%d 1MiB buffers\n", count);
-
-	memory = malloc(count*sizeof(linear));
-	if (memory == NULL) {
-		fprintf(stderr, "Unable to allocate %lld bytes\n",
-			(long long)count*sizeof(linear));
-		return 1;
-	}
-
-	gpu = malloc(sizeof(uint32_t)*count*4);
-	gpu_val = gpu + count;
-	cpu = gpu_val + count;
-	cpu_val = cpu + count;
-
-	for (i = 0; i < count; i++) {
-		gpu[i] = create_bo(fd, start);
-		gpu_val[i] = start;
-		start += WIDTH*HEIGHT;
-	}
-
-	for (i = 0; i < count; i++) {
-		cpu[i] = create_vmap(fd, start, memory+i*WIDTH*HEIGHT);
-		cpu_val[i] = start;
-		start += WIDTH*HEIGHT;;
-	}
-
-	printf("Verifying initialisation...\n");
-	for (i = 0; i < count; i++) {
-		check_gpu(fd, gpu[i], gpu_val[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	printf("Cyclic blits cpu->gpu, forward...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = i % count;
-		int dst = (i + 1) % count;
-
-		copy(fd, gpu[dst], cpu[src]);
-		gpu_val[dst] = cpu_val[src];
-	}
-	for (i = 0; i < count; i++)
-		check_gpu(fd, gpu[i], gpu_val[i]);
-
-	printf("Cyclic blits gpu->cpu, backward...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = (i + 1) % count;
-		int dst = i % count;
-
-		copy(fd, cpu[dst], gpu[src]);
-		cpu_val[dst] = gpu_val[src];
-	}
-	for (i = 0; i < count; i++) {
-		gem_vmap_sync(fd, cpu[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	printf("Random blits...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = random() % count;
-		int dst = random() % count;
-
-		if (random() & 1) {
-			copy(fd, gpu[dst], cpu[src]);
-			gpu_val[dst] = cpu_val[src];
-		} else {
-			copy(fd, cpu[dst], gpu[src]);
-			cpu_val[dst] = gpu_val[src];
-		}
-	}
-	for (i = 0; i < count; i++) {
-		check_gpu(fd, gpu[i], gpu_val[i]);
-		gem_vmap_sync(fd, cpu[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	return 0;
-}
-
-#endif
-- 
1.9.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-03-19 11:13 ` [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
  2014-03-19 11:13   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
  2014-03-19 11:13   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
@ 2014-03-19 11:13   ` Tvrtko Ursulin
  2014-04-17 23:18     ` Volkin, Bradley D
  2 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-03-19 11:13 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This adds a small benchmark for the new userptr functionality.

Apart from basic surface creation and destruction, also tested is the
impact of having userptr surfaces in the process address space. Reason
for that is the impact of MMU notifiers on common address space
operations like munmap() which is per process.

v2:
  * Moved to benchmarks.
  * Added pointer read/write tests.
  * Changed output to say iterations per second instead of
    operations per second.
  * Multiply result by batch size for multi-create* tests
    for a more comparable number with create-destroy test.

v3:
  * Fixed ioctl detection on kernels without MMU_NOTIFIERs.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
---
 Android.mk                         |   3 +-
 benchmarks/.gitignore              |   1 +
 benchmarks/Android.mk              |  36 +++
 benchmarks/Makefile.am             |   7 +-
 benchmarks/Makefile.sources        |   6 +
 benchmarks/gem_userptr_benchmark.c | 513 +++++++++++++++++++++++++++++++++++++
 6 files changed, 558 insertions(+), 8 deletions(-)
 create mode 100644 benchmarks/Android.mk
 create mode 100644 benchmarks/Makefile.sources
 create mode 100644 benchmarks/gem_userptr_benchmark.c

diff --git a/Android.mk b/Android.mk
index 8aeb2d4..0c969b8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,2 +1 @@
-include $(call all-named-subdir-makefiles, lib tests tools)
-
+include $(call all-named-subdir-makefiles, lib tests tools benchmarks)
diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
index ddea6f7..09e5bd8 100644
--- a/benchmarks/.gitignore
+++ b/benchmarks/.gitignore
@@ -1,3 +1,4 @@
+gem_userptr_benchmark
 intel_upload_blit_large
 intel_upload_blit_large_gtt
 intel_upload_blit_large_map
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
new file mode 100644
index 0000000..5bb8ef5
--- /dev/null
+++ b/benchmarks/Android.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(LOCAL_PATH)/Makefile.sources
+
+#================#
+
+define add_benchmark
+    include $(CLEAR_VARS)
+
+    LOCAL_SRC_FILES := $1.c
+
+    LOCAL_CFLAGS += -DHAVE_STRUCT_SYSINFO_TOTALRAM
+    LOCAL_CFLAGS += -DANDROID -UNDEBUG -include "check-ndebug.h"
+    LOCAL_CFLAGS += -std=c99
+    # FIXME: drop once Bionic correctly annotates "noreturn" on pthread_exit
+    LOCAL_CFLAGS += -Wno-error=return-type
+    # Excessive complaining for established cases. Rely on the Linux version warnings.
+    LOCAL_CFLAGS += -Wno-sign-compare
+
+    LOCAL_MODULE := $1
+    LOCAL_MODULE_TAGS := optional
+
+    LOCAL_STATIC_LIBRARIES := libintel_gpu_tools
+
+    LOCAL_SHARED_LIBRARIES := libpciaccess  \
+                              libdrm        \
+                              libdrm_intel
+
+    include $(BUILD_EXECUTABLE)
+endef
+
+#================#
+
+benchmark_list := $(bin_PROGRAMS)
+
+$(foreach item,$(benchmark_list),$(eval $(call add_benchmark,$(item))))
diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
index e2ad784..d173bf4 100644
--- a/benchmarks/Makefile.am
+++ b/benchmarks/Makefile.am
@@ -1,9 +1,4 @@
-
-bin_PROGRAMS = 				\
-	intel_upload_blit_large		\
-	intel_upload_blit_large_gtt	\
-	intel_upload_blit_large_map	\
-	intel_upload_blit_small
+include Makefile.sources
 
 AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
 AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS)
diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
new file mode 100644
index 0000000..fd6c107
--- /dev/null
+++ b/benchmarks/Makefile.sources
@@ -0,0 +1,6 @@
+bin_PROGRAMS =                          \
+        intel_upload_blit_large         \
+        intel_upload_blit_large_gtt     \
+        intel_upload_blit_large_map     \
+        intel_upload_blit_small         \
+        gem_userptr_benchmark
diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
new file mode 100644
index 0000000..218f6f1
--- /dev/null
+++ b/benchmarks/gem_userptr_benchmark.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+ *
+ */
+
+/** @file gem_userptr_benchmark.c
+ *
+ * Benchmark the userptr code and impact of having userptr surfaces
+ * in process address space on some normal operations.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+#define WIDTH 128
+#define HEIGHT 128
+#define PAGE_SIZE 4096
+
+#define LOCAL_I915_GEM_USERPTR       0x34
+#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
+struct local_i915_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint32_t flags;
+#define I915_USERPTR_READ_ONLY (1<<0)
+#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
+	uint32_t handle;
+};
+
+static uint32_t userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static void gem_userptr_test_unsynchronized(void)
+{
+	userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
+}
+
+static void gem_userptr_test_synchronized(void)
+{
+	userptr_flags = 0;
+}
+
+static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	userptr.user_ptr = (uintptr_t)ptr;
+	userptr.user_size = size;
+	userptr.flags = userptr_flags;
+	if (read_only)
+		userptr.flags |= I915_USERPTR_READ_ONLY;
+
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	if (ret)
+		ret = errno;
+	igt_skip_on_f(ret == ENODEV &&
+		      (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) == 0,
+		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
+	if (ret == 0)
+		*handle = userptr.handle;
+
+	return ret;
+}
+
+static uint32_t
+create_userptr(int fd, uint32_t val, uint32_t *ptr)
+{
+	uint32_t handle;
+	int i, ret;
+
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
+	igt_assert(ret == 0);
+	igt_assert(handle != 0);
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		ptr[i] = val++;
+
+	return handle;
+}
+
+static void **handle_ptr_map;
+static unsigned int num_handle_ptr_map;
+
+static void add_handle_ptr(uint32_t handle, void *ptr)
+{
+	if (handle >= num_handle_ptr_map) {
+		handle_ptr_map = realloc(handle_ptr_map,
+					 (handle + 1000) * sizeof(void*));
+		num_handle_ptr_map = handle + 1000;
+	}
+
+	handle_ptr_map[handle] = ptr;
+}
+
+static void *get_handle_ptr(uint32_t handle)
+{
+	return handle_ptr_map[handle];
+}
+
+static void free_handle_ptr(uint32_t handle)
+{
+	igt_assert(handle < num_handle_ptr_map);
+	igt_assert(handle_ptr_map[handle]);
+
+	free(handle_ptr_map[handle]);
+	handle_ptr_map[handle] = NULL;
+}
+
+static uint32_t create_userptr_bo(int fd, int size)
+{
+	void *ptr;
+	uint32_t handle;
+	int ret;
+
+	ret = posix_memalign(&ptr, PAGE_SIZE, size);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
+	igt_assert(ret == 0);
+	add_handle_ptr(handle, ptr);
+
+	return handle;
+}
+
+static void free_userptr_bo(int fd, uint32_t handle)
+{
+	gem_close(fd, handle);
+	free_handle_ptr(handle);
+}
+
+static int has_userptr(int fd)
+{
+	uint32_t handle = 0;
+	void *ptr;
+	uint32_t oldflags;
+	int ret;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+	oldflags = userptr_flags;
+	gem_userptr_test_unsynchronized();
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	userptr_flags = oldflags;
+	if (ret != 0) {
+		free(ptr);
+		return 0;
+	}
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return handle != 0;
+}
+
+static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
+static const unsigned int test_duration_sec = 3;
+
+static volatile unsigned int run_test;
+
+static void alarm_handler(int sig)
+{
+	assert(run_test == 1);
+	run_test = 0;
+}
+
+static void start_test(unsigned int duration)
+{
+	run_test = 1;
+	if (duration == 0)
+		duration = test_duration_sec;
+	signal(SIGALRM, alarm_handler);
+	alarm(duration);
+}
+
+static void exchange_ptr(void *array, unsigned i, unsigned j)
+{
+	void **arr, *tmp;
+	arr = (void **)array;
+
+	tmp = arr[i];
+	arr[i] = arr[j];
+	arr[j] = tmp;
+}
+
+static void test_malloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_malloc_realloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++) {
+			ptr[i] = realloc(ptr[i], 2000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_mmap_unmap(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
+					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+			assert(ptr[i] != MAP_FAILED);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			munmap(ptr[i], 1000);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_ptr_read(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	unsigned long i, loops;
+	register unsigned long v;
+
+	loops = sizeof(linear) / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			v = *p++;
+			v = *p++;
+			v = *p++;
+			v = *p++;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
+}
+
+static void test_ptr_write(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	register unsigned long i, loops;
+
+	loops = sizeof(linear) / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
+}
+
+static void test_impact(int fd)
+{
+	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
+	unsigned int subtest, i;
+	uint32_t handles[nr_bos[total-1]];
+	void *ptr;
+	char buffer[sizeof(linear)];
+
+	for (subtest = 0; subtest < total; subtest++) {
+		for (i = 0; i < nr_bos[subtest]; i++)
+			handles[i] = create_userptr_bo(fd, sizeof(linear));
+
+		if (nr_bos[subtest] > 0)
+			ptr = get_handle_ptr(handles[0]);
+		else
+			ptr = buffer;
+
+		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_read(ptr);
+
+		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_write(ptr);
+
+		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(0);
+		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(1);
+
+		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(0);
+		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(1);
+
+		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(0);
+		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(1);
+
+		for (i = 0; i < nr_bos[subtest]; i++)
+			free_userptr_bo(fd, handles[i]);
+	}
+}
+
+static void test_single(int fd)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handle = 0;
+	unsigned long iter = 0;
+	int ret;
+	unsigned long map_size = sizeof(linear) + PAGE_SIZE - 1;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+					& ~(PAGE_SIZE - 1));
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &handle);
+		assert(ret == 0);
+		gem_close(fd, handle);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_multiple(int fd, unsigned int batch, int random)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handles[10000];
+	int map[10000];
+	unsigned long iter = 0;
+	int ret;
+	int i;
+	unsigned long map_size = batch * sizeof(linear) + PAGE_SIZE - 1;
+
+	assert(batch < (sizeof(handles) / sizeof(handles[0])));
+	assert(batch < (sizeof(map) / sizeof(map[0])));
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
+				& ~(PAGE_SIZE - 1));
+
+	for (i = 0; i < batch; i++)
+		map[i] = i;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++) {
+			ret = gem_userptr(fd, bo_ptr + map[i] * sizeof(linear),
+						sizeof(linear),
+						0, &handles[i]);
+			assert(ret == 0);
+		}
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++)
+			gem_close(fd, handles[map[i]]);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter * batch / test_duration_sec);
+}
+
+static void test_userptr(int fd)
+{
+	printf("create-destroy                = ");
+	test_single(fd);
+
+	printf("multi-create-destroy          = ");
+	test_multiple(fd, 100, 0);
+
+	printf("multi-create-destroy-random   = ");
+	test_multiple(fd, 100, 1);
+}
+
+int main(int argc, char **argv)
+{
+	int fd = -1, ret;
+
+	igt_skip_on_simulation();
+
+	igt_subtest_init(argc, argv);
+
+	fd = drm_open_any();
+	igt_assert(fd >= 0);
+
+	ret = has_userptr(fd);
+	igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
+			strerror(errno), ret);
+
+
+	gem_userptr_test_unsynchronized();
+
+	igt_subtest("userptr-unsync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-unsync")
+		test_impact(fd);
+
+	gem_userptr_test_synchronized();
+
+	igt_subtest("userptr-sync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-sync")
+		test_impact(fd);
+
+	igt_exit();
+
+	return 0;
+}
-- 
1.9.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-03-19 11:13   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
@ 2014-04-17 23:18     ` Volkin, Bradley D
  2014-04-22 18:59       ` Daniel Vetter
  2014-04-23 13:28       ` Tvrtko Ursulin
  0 siblings, 2 replies; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-17 23:18 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

On Wed, Mar 19, 2014 at 04:13:06AM -0700, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> This adds a small benchmark for the new userptr functionality.
> 
> Apart from basic surface creation and destruction, also tested is the
> impact of having userptr surfaces in the process address space. Reason
> for that is the impact of MMU notifiers on common address space
> operations like munmap() which is per process.
> 
> v2:
>   * Moved to benchmarks.
>   * Added pointer read/write tests.
>   * Changed output to say iterations per second instead of
>     operations per second.
>   * Multiply result by batch size for multi-create* tests
>     for a more comparable number with create-destroy test.
> 
> v3:
>   * Fixed ioctl detection on kernels without MMU_NOTIFIERs.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  Android.mk                         |   3 +-
>  benchmarks/.gitignore              |   1 +
>  benchmarks/Android.mk              |  36 +++
>  benchmarks/Makefile.am             |   7 +-
>  benchmarks/Makefile.sources        |   6 +
>  benchmarks/gem_userptr_benchmark.c | 513 +++++++++++++++++++++++++++++++++++++
>  6 files changed, 558 insertions(+), 8 deletions(-)
>  create mode 100644 benchmarks/Android.mk
>  create mode 100644 benchmarks/Makefile.sources
>  create mode 100644 benchmarks/gem_userptr_benchmark.c
> 
> diff --git a/Android.mk b/Android.mk
> index 8aeb2d4..0c969b8 100644
> --- a/Android.mk
> +++ b/Android.mk
> @@ -1,2 +1 @@
> -include $(call all-named-subdir-makefiles, lib tests tools)
> -
> +include $(call all-named-subdir-makefiles, lib tests tools benchmarks)
> diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
> index ddea6f7..09e5bd8 100644
> --- a/benchmarks/.gitignore
> +++ b/benchmarks/.gitignore
> @@ -1,3 +1,4 @@
> +gem_userptr_benchmark
>  intel_upload_blit_large
>  intel_upload_blit_large_gtt
>  intel_upload_blit_large_map
> diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
> new file mode 100644
> index 0000000..5bb8ef5
> --- /dev/null
> +++ b/benchmarks/Android.mk
> @@ -0,0 +1,36 @@
> +LOCAL_PATH := $(call my-dir)
> +
> +include $(LOCAL_PATH)/Makefile.sources
> +
> +#================#
> +
> +define add_benchmark
> +    include $(CLEAR_VARS)
> +
> +    LOCAL_SRC_FILES := $1.c
> +
> +    LOCAL_CFLAGS += -DHAVE_STRUCT_SYSINFO_TOTALRAM
> +    LOCAL_CFLAGS += -DANDROID -UNDEBUG -include "check-ndebug.h"
> +    LOCAL_CFLAGS += -std=c99
> +    # FIXME: drop once Bionic correctly annotates "noreturn" on pthread_exit
> +    LOCAL_CFLAGS += -Wno-error=return-type
> +    # Excessive complaining for established cases. Rely on the Linux version warnings.
> +    LOCAL_CFLAGS += -Wno-sign-compare
> +
> +    LOCAL_MODULE := $1
> +    LOCAL_MODULE_TAGS := optional
> +
> +    LOCAL_STATIC_LIBRARIES := libintel_gpu_tools
> +
> +    LOCAL_SHARED_LIBRARIES := libpciaccess  \
> +                              libdrm        \
> +                              libdrm_intel
> +
> +    include $(BUILD_EXECUTABLE)
> +endef
> +
> +#================#
> +
> +benchmark_list := $(bin_PROGRAMS)
> +
> +$(foreach item,$(benchmark_list),$(eval $(call add_benchmark,$(item))))
> diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
> index e2ad784..d173bf4 100644
> --- a/benchmarks/Makefile.am
> +++ b/benchmarks/Makefile.am
> @@ -1,9 +1,4 @@
> -
> -bin_PROGRAMS = 				\
> -	intel_upload_blit_large		\
> -	intel_upload_blit_large_gtt	\
> -	intel_upload_blit_large_map	\
> -	intel_upload_blit_small
> +include Makefile.sources
>  
>  AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
>  AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS)
> diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
> new file mode 100644
> index 0000000..fd6c107
> --- /dev/null
> +++ b/benchmarks/Makefile.sources
> @@ -0,0 +1,6 @@
> +bin_PROGRAMS =                          \
> +        intel_upload_blit_large         \
> +        intel_upload_blit_large_gtt     \
> +        intel_upload_blit_large_map     \
> +        intel_upload_blit_small         \
> +        gem_userptr_benchmark

You might split the makefile cleanup aspect of this into a separate
patch, but I'm fine either way.

> diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
> new file mode 100644
> index 0000000..218f6f1
> --- /dev/null
> +++ b/benchmarks/gem_userptr_benchmark.c
> @@ -0,0 +1,513 @@
> +/*
> + * Copyright © 2014 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> + *
> + */
> +
> +/** @file gem_userptr_benchmark.c
> + *
> + * Benchmark the userptr code and impact of having userptr surfaces
> + * in process address space on some normal operations.
> + *
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <sys/stat.h>
> +#include <sys/time.h>
> +#include <sys/mman.h>
> +#include "drm.h"
> +#include "i915_drm.h"
> +#include "drmtest.h"
> +#include "intel_bufmgr.h"
> +#include "intel_batchbuffer.h"
> +#include "intel_gpu_tools.h"
> +
> +#define WIDTH 128
> +#define HEIGHT 128
> +#define PAGE_SIZE 4096
> +
> +#define LOCAL_I915_GEM_USERPTR       0x34
> +#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
> +struct local_i915_gem_userptr {
> +	uint64_t user_ptr;
> +	uint64_t user_size;
> +	uint32_t flags;
> +#define I915_USERPTR_READ_ONLY (1<<0)
> +#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
> +	uint32_t handle;
> +};
> +
> +static uint32_t userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
> +
> +static uint32_t linear[WIDTH*HEIGHT];

I may have missed it, but I don't think we use this variable except
to do sizeof(linear). If that's the case, a constant for the buffer
size might make the code more readable.

> +
> +static void gem_userptr_test_unsynchronized(void)
> +{
> +	userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
> +}
> +
> +static void gem_userptr_test_synchronized(void)
> +{
> +	userptr_flags = 0;
> +}
> +
> +static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
> +{
> +	struct local_i915_gem_userptr userptr;
> +	int ret;
> +
> +	userptr.user_ptr = (uintptr_t)ptr;
> +	userptr.user_size = size;
> +	userptr.flags = userptr_flags;
> +	if (read_only)
> +		userptr.flags |= I915_USERPTR_READ_ONLY;
> +
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	if (ret)
> +		ret = errno;
> +	igt_skip_on_f(ret == ENODEV &&
> +		      (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) == 0,
> +		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
> +	if (ret == 0)
> +		*handle = userptr.handle;
> +
> +	return ret;
> +}
> +
> +static uint32_t
> +create_userptr(int fd, uint32_t val, uint32_t *ptr)
> +{
> +	uint32_t handle;
> +	int i, ret;
> +
> +	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
> +	igt_assert(ret == 0);
> +	igt_assert(handle != 0);
> +
> +	/* Fill the BO with dwords starting at val */
> +	for (i = 0; i < WIDTH*HEIGHT; i++)
> +		ptr[i] = val++;
> +
> +	return handle;
> +}

I don't see that this function is used in this test.

> +
> +static void **handle_ptr_map;
> +static unsigned int num_handle_ptr_map;

I'd prefer that we explicitly initialize at least num_handle_ptr_map.

> +
> +static void add_handle_ptr(uint32_t handle, void *ptr)
> +{
> +	if (handle >= num_handle_ptr_map) {
> +		handle_ptr_map = realloc(handle_ptr_map,
> +					 (handle + 1000) * sizeof(void*));
> +		num_handle_ptr_map = handle + 1000;
> +	}
> +
> +	handle_ptr_map[handle] = ptr;
> +}
> +
> +static void *get_handle_ptr(uint32_t handle)
> +{
> +	return handle_ptr_map[handle];
> +}
> +
> +static void free_handle_ptr(uint32_t handle)
> +{
> +	igt_assert(handle < num_handle_ptr_map);
> +	igt_assert(handle_ptr_map[handle]);
> +
> +	free(handle_ptr_map[handle]);
> +	handle_ptr_map[handle] = NULL;
> +}
> +
> +static uint32_t create_userptr_bo(int fd, int size)
> +{
> +	void *ptr;
> +	uint32_t handle;
> +	int ret;
> +
> +	ret = posix_memalign(&ptr, PAGE_SIZE, size);
> +	igt_assert(ret == 0);
> +
> +	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
> +	igt_assert(ret == 0);
> +	add_handle_ptr(handle, ptr);
> +
> +	return handle;
> +}
> +
> +static void free_userptr_bo(int fd, uint32_t handle)
> +{
> +	gem_close(fd, handle);
> +	free_handle_ptr(handle);
> +}
> +
> +static int has_userptr(int fd)
> +{
> +	uint32_t handle = 0;
> +	void *ptr;
> +	uint32_t oldflags;
> +	int ret;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +	oldflags = userptr_flags;
> +	gem_userptr_test_unsynchronized();
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	userptr_flags = oldflags;
> +	if (ret != 0) {
> +		free(ptr);
> +		return 0;
> +	}
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return handle != 0;
> +}
> +
> +static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
> +static const unsigned int test_duration_sec = 3;
> +
> +static volatile unsigned int run_test;
> +
> +static void alarm_handler(int sig)
> +{
> +	assert(run_test == 1);
> +	run_test = 0;
> +}
> +
> +static void start_test(unsigned int duration)
> +{
> +	run_test = 1;
> +	if (duration == 0)
> +		duration = test_duration_sec;
> +	signal(SIGALRM, alarm_handler);
> +	alarm(duration);
> +}
> +
> +static void exchange_ptr(void *array, unsigned i, unsigned j)
> +{
> +	void **arr, *tmp;
> +	arr = (void **)array;
> +
> +	tmp = arr[i];
> +	arr[i] = arr[j];
> +	arr[j] = tmp;
> +}
> +
> +static void test_malloc_free(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = malloc(1000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			free(ptr[i]);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_malloc_realloc_free(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = malloc(1000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = realloc(ptr[i], 2000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			free(ptr[i]);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_mmap_unmap(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
> +					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +			assert(ptr[i] != MAP_FAILED);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			munmap(ptr[i], 1000);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_ptr_read(void *ptr)
> +{
> +	unsigned long iter = 0;
> +	volatile unsigned long *p;
> +	unsigned long i, loops;
> +	register unsigned long v;
> +
> +	loops = sizeof(linear) / sizeof(unsigned long) / 4;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		p = (unsigned long *)ptr;
> +		for (i = 0; i < loops; i++) {
> +			v = *p++;
> +			v = *p++;
> +			v = *p++;
> +			v = *p++;
> +		}
> +		iter++;
> +	}
> +
> +	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
> +}
> +
> +static void test_ptr_write(void *ptr)
> +{
> +	unsigned long iter = 0;
> +	volatile unsigned long *p;
> +	register unsigned long i, loops;
> +
> +	loops = sizeof(linear) / sizeof(unsigned long) / 4;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		p = (unsigned long *)ptr;
> +		for (i = 0; i < loops; i++) {
> +			*p++ = i;
> +			*p++ = i;
> +			*p++ = i;
> +			*p++ = i;
> +		}
> +		iter++;
> +	}
> +
> +	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
> +}
> +
> +static void test_impact(int fd)
> +{
> +	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
> +	unsigned int subtest, i;
> +	uint32_t handles[nr_bos[total-1]];
> +	void *ptr;
> +	char buffer[sizeof(linear)];
> +
> +	for (subtest = 0; subtest < total; subtest++) {
> +		for (i = 0; i < nr_bos[subtest]; i++)
> +			handles[i] = create_userptr_bo(fd, sizeof(linear));
> +
> +		if (nr_bos[subtest] > 0)
> +			ptr = get_handle_ptr(handles[0]);
> +		else
> +			ptr = buffer;
> +
> +		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
> +		test_ptr_read(ptr);
> +
> +		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
> +		test_ptr_write(ptr);
> +
> +		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
> +		test_malloc_free(0);
> +		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
> +		test_malloc_free(1);
> +
> +		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
> +		test_malloc_realloc_free(0);
> +		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
> +		test_malloc_realloc_free(1);
> +
> +		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
> +		test_mmap_unmap(0);
> +		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
> +		test_mmap_unmap(1);
> +
> +		for (i = 0; i < nr_bos[subtest]; i++)
> +			free_userptr_bo(fd, handles[i]);
> +	}
> +}
> +
> +static void test_single(int fd)
> +{
> +	char *ptr, *bo_ptr;
> +	uint32_t handle = 0;
> +	unsigned long iter = 0;
> +	int ret;
> +	unsigned long map_size = sizeof(linear) + PAGE_SIZE - 1;
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
> +					& ~(PAGE_SIZE - 1));

You might add an ALIGN macro in this file or a suitable header. A couple of
.c files in lib/ individually define one already.

Brad

> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &handle);
> +		assert(ret == 0);
> +		gem_close(fd, handle);
> +		iter++;
> +	}
> +
> +	munmap(ptr, map_size);
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_multiple(int fd, unsigned int batch, int random)
> +{
> +	char *ptr, *bo_ptr;
> +	uint32_t handles[10000];
> +	int map[10000];
> +	unsigned long iter = 0;
> +	int ret;
> +	int i;
> +	unsigned long map_size = batch * sizeof(linear) + PAGE_SIZE - 1;
> +
> +	assert(batch < (sizeof(handles) / sizeof(handles[0])));
> +	assert(batch < (sizeof(map) / sizeof(map[0])));
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
> +				& ~(PAGE_SIZE - 1));
> +
> +	for (i = 0; i < batch; i++)
> +		map[i] = i;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		if (random)
> +			igt_permute_array(map, batch, igt_exchange_int);
> +		for (i = 0; i < batch; i++) {
> +			ret = gem_userptr(fd, bo_ptr + map[i] * sizeof(linear),
> +						sizeof(linear),
> +						0, &handles[i]);
> +			assert(ret == 0);
> +		}
> +		if (random)
> +			igt_permute_array(map, batch, igt_exchange_int);
> +		for (i = 0; i < batch; i++)
> +			gem_close(fd, handles[map[i]]);
> +		iter++;
> +	}
> +
> +	munmap(ptr, map_size);
> +
> +	printf("%8lu iter/s\n", iter * batch / test_duration_sec);
> +}
> +
> +static void test_userptr(int fd)
> +{
> +	printf("create-destroy                = ");
> +	test_single(fd);
> +
> +	printf("multi-create-destroy          = ");
> +	test_multiple(fd, 100, 0);
> +
> +	printf("multi-create-destroy-random   = ");
> +	test_multiple(fd, 100, 1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int fd = -1, ret;
> +
> +	igt_skip_on_simulation();
> +
> +	igt_subtest_init(argc, argv);
> +
> +	fd = drm_open_any();
> +	igt_assert(fd >= 0);
> +
> +	ret = has_userptr(fd);
> +	igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
> +			strerror(errno), ret);
> +
> +
> +	gem_userptr_test_unsynchronized();
> +
> +	igt_subtest("userptr-unsync")
> +		test_userptr(fd);
> +
> +	igt_subtest("userptr-impact-unsync")
> +		test_impact(fd);
> +
> +	gem_userptr_test_synchronized();
> +
> +	igt_subtest("userptr-sync")
> +		test_userptr(fd);
> +
> +	igt_subtest("userptr-impact-sync")
> +		test_impact(fd);
> +
> +	igt_exit();
> +
> +	return 0;
> +}
> -- 
> 1.9.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case
  2014-03-19 11:13   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
@ 2014-04-17 23:20     ` Volkin, Bradley D
  0 siblings, 0 replies; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-17 23:20 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

On Wed, Mar 19, 2014 at 04:13:05AM -0700, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> No need for the old test case once the new one was added.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Reviewed-by: Brad Volkin <bradley.d.volkin@intel.com>

> ---
>  tests/.gitignore       |   1 -
>  tests/Makefile.sources |   1 -
>  tests/gem_vmap_blits.c | 344 -------------------------------------------------
>  3 files changed, 346 deletions(-)
>  delete mode 100644 tests/gem_vmap_blits.c
> 
> diff --git a/tests/.gitignore b/tests/.gitignore
> index ff1eff5..c600823 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -93,7 +93,6 @@ gem_tiled_swapping
>  gem_tiling_max_stride
>  gem_unfence_active_buffers
>  gem_unref_active_buffers
> -gem_vmap_blits
>  gem_userptr_blits
>  gem_wait_render_timeout
>  gem_write_read_ring_switch
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 240bd99..610bbf5 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -118,7 +118,6 @@ TESTS_progs = \
>  	gem_tiling_max_stride \
>  	gem_unfence_active_buffers \
>  	gem_unref_active_buffers \
> -	gem_vmap_blits \
>  	gem_userptr_blits \
>  	gem_wait_render_timeout \
>  	gen3_mixed_blits \
> diff --git a/tests/gem_vmap_blits.c b/tests/gem_vmap_blits.c
> deleted file mode 100644
> index 48297af..0000000
> --- a/tests/gem_vmap_blits.c
> +++ /dev/null
> @@ -1,344 +0,0 @@
> -/*
> - * Copyright © 2009,2011 Intel Corporation
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> - *
> - * Authors:
> - *    Eric Anholt <eric@anholt.net>
> - *    Chris Wilson <chris@chris-wilson.co.uk>
> - *
> - */
> -
> -/** @file gem_vmap_blits.c
> - *
> - * This is a test of doing many blits using a mixture of normal system pages
> - * and uncached linear buffers, with a working set larger than the
> - * aperture size.
> - *
> - * The goal is to simply ensure the basics work.
> - */
> -
> -#include <stdlib.h>
> -#include <stdio.h>
> -#include <string.h>
> -#include <fcntl.h>
> -#include <inttypes.h>
> -#include <errno.h>
> -#include <sys/stat.h>
> -#include <sys/time.h>
> -#include "drm.h"
> -#include "i915_drm.h"
> -#include "drmtest.h"
> -#include "intel_bufmgr.h"
> -#include "intel_batchbuffer.h"
> -#include "intel_gpu_tools.h"
> -
> -#if !defined(I915_PARAM_HAS_VMAP)
> -#pragma message("No vmap support in drm, skipping")
> -int main(int argc, char **argv)
> -{
> -	fprintf(stderr, "No vmap support in drm.\n");
> -	return 77;
> -}
> -#else
> -
> -#define WIDTH 512
> -#define HEIGHT 512
> -
> -static uint32_t linear[WIDTH*HEIGHT];
> -
> -static uint32_t gem_vmap(int fd, void *ptr, int size, int read_only)
> -{
> -	struct drm_i915_gem_vmap vmap;
> -
> -	vmap.user_ptr = (uintptr_t)ptr;
> -	vmap.user_size = size;
> -	vmap.flags = 0;
> -	if (read_only)
> -		vmap.flags |= I915_VMAP_READ_ONLY;
> -
> -	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_VMAP, &vmap))
> -		return 0;
> -
> -	return vmap.handle;
> -}
> -
> -
> -static void gem_vmap_sync(int fd, uint32_t handle)
> -{
> -	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> -}
> -
> -static void
> -copy(int fd, uint32_t dst, uint32_t src)
> -{
> -	uint32_t batch[10];
> -	struct drm_i915_gem_relocation_entry reloc[2];
> -	struct drm_i915_gem_exec_object2 obj[3];
> -	struct drm_i915_gem_execbuffer2 exec;
> -	uint32_t handle;
> -	int ret;
> -
> -	batch[0] = XY_SRC_COPY_BLT_CMD |
> -		  XY_SRC_COPY_BLT_WRITE_ALPHA |
> -		  XY_SRC_COPY_BLT_WRITE_RGB | 6;
> -	batch[1] = (3 << 24) | /* 32 bits */
> -		  (0xcc << 16) | /* copy ROP */
> -		  WIDTH*4;
> -	batch[2] = 0; /* dst x1,y1 */
> -	batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
> -	batch[4] = 0; /* dst reloc */
> -	batch[5] = 0; /* src x1,y1 */
> -	batch[6] = WIDTH*4;
> -	batch[7] = 0; /* src reloc */
> -	batch[8] = MI_BATCH_BUFFER_END;
> -	batch[9] = MI_NOOP;
> -
> -	handle = gem_create(fd, 4096);
> -	gem_write(fd, handle, 0, batch, sizeof(batch));
> -
> -	reloc[0].target_handle = dst;
> -	reloc[0].delta = 0;
> -	reloc[0].offset = 4 * sizeof(batch[0]);
> -	reloc[0].presumed_offset = 0;
> -	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
> -	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
> -
> -	reloc[1].target_handle = src;
> -	reloc[1].delta = 0;
> -	reloc[1].offset = 7 * sizeof(batch[0]);
> -	reloc[1].presumed_offset = 0;
> -	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
> -	reloc[1].write_domain = 0;
> -
> -	obj[0].handle = dst;
> -	obj[0].relocation_count = 0;
> -	obj[0].relocs_ptr = 0;
> -	obj[0].alignment = 0;
> -	obj[0].offset = 0;
> -	obj[0].flags = 0;
> -	obj[0].rsvd1 = 0;
> -	obj[0].rsvd2 = 0;
> -
> -	obj[1].handle = src;
> -	obj[1].relocation_count = 0;
> -	obj[1].relocs_ptr = 0;
> -	obj[1].alignment = 0;
> -	obj[1].offset = 0;
> -	obj[1].flags = 0;
> -	obj[1].rsvd1 = 0;
> -	obj[1].rsvd2 = 0;
> -
> -	obj[2].handle = handle;
> -	obj[2].relocation_count = 2;
> -	obj[2].relocs_ptr = (uintptr_t)reloc;
> -	obj[2].alignment = 0;
> -	obj[2].offset = 0;
> -	obj[2].flags = 0;
> -	obj[2].rsvd1 = obj[2].rsvd2 = 0;
> -
> -	exec.buffers_ptr = (uintptr_t)obj;
> -	exec.buffer_count = 3;
> -	exec.batch_start_offset = 0;
> -	exec.batch_len = sizeof(batch);
> -	exec.DR1 = exec.DR4 = 0;
> -	exec.num_cliprects = 0;
> -	exec.cliprects_ptr = 0;
> -	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
> -	exec.rsvd1 = exec.rsvd2 = 0;
> -
> -	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> -	while (ret && errno == EBUSY) {
> -		drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
> -		ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> -	}
> -	igt_assert(ret == 0);
> -
> -	gem_close(fd, handle);
> -}
> -
> -static uint32_t
> -create_vmap(int fd, uint32_t val, uint32_t *ptr)
> -{
> -	uint32_t handle;
> -	int i;
> -
> -	handle = gem_vmap(fd, ptr, sizeof(linear), 0);
> -
> -	/* Fill the BO with dwords starting at val */
> -	for (i = 0; i < WIDTH*HEIGHT; i++)
> -		ptr[i] = val++;
> -
> -	return handle;
> -}
> -
> -static uint32_t
> -create_bo(int fd, uint32_t val)
> -{
> -	uint32_t handle;
> -	int i;
> -
> -	handle = gem_create(fd, sizeof(linear));
> -
> -	/* Fill the BO with dwords starting at val */
> -	for (i = 0; i < WIDTH*HEIGHT; i++)
> -		linear[i] = val++;
> -	gem_write(fd, handle, 0, linear, sizeof(linear));
> -
> -	return handle;
> -}
> -
> -static void
> -check_cpu(uint32_t *ptr, uint32_t val)
> -{
> -	int i;
> -
> -	for (i = 0; i < WIDTH*HEIGHT; i++) {
> -		if (ptr[i] != val) {
> -			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
> -				"at offset 0x%08x\n",
> -				val, ptr[i], i * 4);
> -			abort();
> -		}
> -		val++;
> -	}
> -}
> -
> -static void
> -check_gpu(int fd, uint32_t handle, uint32_t val)
> -{
> -	gem_read(fd, handle, 0, linear, sizeof(linear));
> -	check_cpu(linear, val);
> -}
> -
> -static int has_vmap(int fd)
> -{
> -	drm_i915_getparam_t gp;
> -	int i;
> -
> -	gp.param = I915_PARAM_HAS_VMAP;
> -	gp.value = &i;
> -
> -	return drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0 && i > 0;
> -}
> -
> -int main(int argc, char **argv)
> -{
> -	uint32_t *memory;
> -	uint32_t *cpu, *cpu_val;
> -	uint32_t *gpu, *gpu_val;
> -	uint32_t start = 0;
> -	int i, fd, count;
> -
> -	igt_simple_init();
> -
> -	igt_skip_on_simulation();
> -
> -	fd = drm_open_any();
> -
> -	if (!has_vmap(fd)) {
> -		fprintf(stderr, "No vmap support, ignoring.\n");
> -		return 77;
> -	}
> -
> -	count = 0;
> -	if (argc > 1)
> -		count = atoi(argv[1]);
> -	if (count == 0)
> -		count = 3 * gem_aperture_size(fd) / (1024*1024) / 4;
> -	printf("Using 2x%d 1MiB buffers\n", count);
> -
> -	memory = malloc(count*sizeof(linear));
> -	if (memory == NULL) {
> -		fprintf(stderr, "Unable to allocate %lld bytes\n",
> -			(long long)count*sizeof(linear));
> -		return 1;
> -	}
> -
> -	gpu = malloc(sizeof(uint32_t)*count*4);
> -	gpu_val = gpu + count;
> -	cpu = gpu_val + count;
> -	cpu_val = cpu + count;
> -
> -	for (i = 0; i < count; i++) {
> -		gpu[i] = create_bo(fd, start);
> -		gpu_val[i] = start;
> -		start += WIDTH*HEIGHT;
> -	}
> -
> -	for (i = 0; i < count; i++) {
> -		cpu[i] = create_vmap(fd, start, memory+i*WIDTH*HEIGHT);
> -		cpu_val[i] = start;
> -		start += WIDTH*HEIGHT;;
> -	}
> -
> -	printf("Verifying initialisation...\n");
> -	for (i = 0; i < count; i++) {
> -		check_gpu(fd, gpu[i], gpu_val[i]);
> -		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> -	}
> -
> -	printf("Cyclic blits cpu->gpu, forward...\n");
> -	for (i = 0; i < count * 4; i++) {
> -		int src = i % count;
> -		int dst = (i + 1) % count;
> -
> -		copy(fd, gpu[dst], cpu[src]);
> -		gpu_val[dst] = cpu_val[src];
> -	}
> -	for (i = 0; i < count; i++)
> -		check_gpu(fd, gpu[i], gpu_val[i]);
> -
> -	printf("Cyclic blits gpu->cpu, backward...\n");
> -	for (i = 0; i < count * 4; i++) {
> -		int src = (i + 1) % count;
> -		int dst = i % count;
> -
> -		copy(fd, cpu[dst], gpu[src]);
> -		cpu_val[dst] = gpu_val[src];
> -	}
> -	for (i = 0; i < count; i++) {
> -		gem_vmap_sync(fd, cpu[i]);
> -		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> -	}
> -
> -	printf("Random blits...\n");
> -	for (i = 0; i < count * 4; i++) {
> -		int src = random() % count;
> -		int dst = random() % count;
> -
> -		if (random() & 1) {
> -			copy(fd, gpu[dst], cpu[src]);
> -			gpu_val[dst] = cpu_val[src];
> -		} else {
> -			copy(fd, cpu[dst], gpu[src]);
> -			cpu_val[dst] = gpu_val[src];
> -		}
> -	}
> -	for (i = 0; i < count; i++) {
> -		check_gpu(fd, gpu[i], gpu_val[i]);
> -		gem_vmap_sync(fd, cpu[i]);
> -		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> -	}
> -
> -	return 0;
> -}
> -
> -#endif
> -- 
> 1.9.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-03-19 11:13   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
@ 2014-04-18 17:10     ` Volkin, Bradley D
  2014-04-23 13:33       ` Tvrtko Ursulin
  0 siblings, 1 reply; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-18 17:10 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

On Wed, Mar 19, 2014 at 04:13:04AM -0700, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> A set of userptr test cases to support the new feature.
> 
> For the eviction and swapping stress testing I have extracted
> some common behaviour from gem_evict_everything and made both
> test cases use it to avoid duplicating the code.
> 
> Both unsynchronized and synchronized userptr objects are
> tested but the latter set of tests will be skipped if kernel
> is compiled without MMU_NOTIFIERS.
> 
> Also, with 32-bit userspace swapping tests are skipped if
> the system has a lot more RAM than process address space.
> Forking swapping tests are not skipped since they can still
> trigger swapping by cumulative effect.
> 
> v2:
>    * Fixed dmabuf test.
>    * Added test for rejecting read-only.
>    * Fixed ioctl detection for latest kernel patch.
> 
> v3:
>    * Updated copy() for Gen8+.
>    * Fixed ioctl detection on kernels without MMU_NOTIFIERs.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

A number of the comments I made on patch 3 apply here as well.
The sizeof(linear) thing is more prevalent in this test, though
it looks like linear is at least used. Other than those comments
this looks good to me.

Thanks,
Brad

> ---
>  tests/.gitignore          |    1 +
>  tests/Makefile.sources    |    1 +
>  tests/gem_userptr_blits.c | 1244 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1246 insertions(+)
>  create mode 100644 tests/gem_userptr_blits.c
> 
> diff --git a/tests/.gitignore b/tests/.gitignore
> index 623a621..ff1eff5 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -94,6 +94,7 @@ gem_tiling_max_stride
>  gem_unfence_active_buffers
>  gem_unref_active_buffers
>  gem_vmap_blits
> +gem_userptr_blits
>  gem_wait_render_timeout
>  gem_write_read_ring_switch
>  gen3_mixed_blits
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 88866ac..240bd99 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -119,6 +119,7 @@ TESTS_progs = \
>  	gem_unfence_active_buffers \
>  	gem_unref_active_buffers \
>  	gem_vmap_blits \
> +	gem_userptr_blits \
>  	gem_wait_render_timeout \
>  	gen3_mixed_blits \
>  	gen3_render_linear_blits \
> diff --git a/tests/gem_userptr_blits.c b/tests/gem_userptr_blits.c
> new file mode 100644
> index 0000000..1637297
> --- /dev/null
> +++ b/tests/gem_userptr_blits.c
> @@ -0,0 +1,1244 @@
> +/*
> + * Copyright © 2009-2014 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Eric Anholt <eric@anholt.net>
> + *    Chris Wilson <chris@chris-wilson.co.uk>
> + *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> + *
> + */
> +
> +/** @file gem_userptr_blits.c
> + *
> + * This is a test of doing many blits using a mixture of normal system pages
> + * and uncached linear buffers, with a working set larger than the
> + * aperture size.
> + *
> + * The goal is to simply ensure the basics work.
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <sys/stat.h>
> +#include <sys/time.h>
> +#include <sys/mman.h>
> +#include "drm.h"
> +#include "i915_drm.h"
> +#include "drmtest.h"
> +#include "intel_bufmgr.h"
> +#include "intel_batchbuffer.h"
> +#include "intel_gpu_tools.h"
> +
> +#include "eviction_common.c"
> +
> +#define WIDTH 512
> +#define HEIGHT 512
> +#define PAGE_SIZE 4096
> +
> +#define LOCAL_I915_GEM_USERPTR       0x34
> +#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
> +struct local_i915_gem_userptr {
> +	uint64_t user_ptr;
> +	uint64_t user_size;
> +	uint32_t flags;
> +#define I915_USERPTR_READ_ONLY (1<<0)
> +#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
> +	uint32_t handle;
> +};
> +
> +static uint32_t userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
> +
> +static uint32_t linear[WIDTH*HEIGHT];
> +
> +static void gem_userptr_test_unsynchronized(void)
> +{
> +	userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
> +}
> +
> +static void gem_userptr_test_synchronized(void)
> +{
> +	userptr_flags = 0;
> +}
> +
> +static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
> +{
> +	struct local_i915_gem_userptr userptr;
> +	int ret;
> +
> +	userptr.user_ptr = (uintptr_t)ptr;
> +	userptr.user_size = size;
> +	userptr.flags = userptr_flags;
> +	if (read_only)
> +		userptr.flags |= I915_USERPTR_READ_ONLY;
> +
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	if (ret)
> +		ret = errno;
> +	igt_skip_on_f(ret == ENODEV &&
> +		      (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) == 0 &&
> +		      !read_only,
> +		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
> +	if (ret == 0)
> +		*handle = userptr.handle;
> +
> +	return ret;
> +}
> +
> +
> +static void gem_userptr_sync(int fd, uint32_t handle)
> +{
> +	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> +}
> +
> +static void
> +copy(int fd, uint32_t dst, uint32_t src, unsigned int error)
> +{
> +	uint32_t batch[12];
> +	struct drm_i915_gem_relocation_entry reloc[2];
> +	struct drm_i915_gem_exec_object2 obj[3];
> +	struct drm_i915_gem_execbuffer2 exec;
> +	uint32_t handle;
> +	int ret, i=0;
> +
> +	batch[i++] = XY_SRC_COPY_BLT_CMD |
> +		  XY_SRC_COPY_BLT_WRITE_ALPHA |
> +		  XY_SRC_COPY_BLT_WRITE_RGB;
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i - 1] |= 8;
> +	else
> +		batch[i - 1] |= 6;
> +
> +	batch[i++] = (3 << 24) | /* 32 bits */
> +		  (0xcc << 16) | /* copy ROP */
> +		  WIDTH*4;
> +	batch[i++] = 0; /* dst x1,y1 */
> +	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
> +	batch[i++] = 0; /* dst reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = 0; /* src x1,y1 */
> +	batch[i++] = WIDTH*4;
> +	batch[i++] = 0; /* src reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = MI_BATCH_BUFFER_END;
> +	batch[i++] = MI_NOOP;
> +
> +	handle = gem_create(fd, 4096);
> +	gem_write(fd, handle, 0, batch, sizeof(batch));
> +
> +	reloc[0].target_handle = dst;
> +	reloc[0].delta = 0;
> +	reloc[0].offset = 4 * sizeof(batch[0]);
> +	reloc[0].presumed_offset = 0;
> +	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
> +	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
> +
> +	reloc[1].target_handle = src;
> +	reloc[1].delta = 0;
> +	reloc[1].offset = 7 * sizeof(batch[0]);
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		reloc[1].offset += sizeof(batch[0]);
> +	reloc[1].presumed_offset = 0;
> +	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
> +	reloc[1].write_domain = 0;
> +
> +	obj[0].handle = dst;
> +	obj[0].relocation_count = 0;
> +	obj[0].relocs_ptr = 0;
> +	obj[0].alignment = 0;
> +	obj[0].offset = 0;
> +	obj[0].flags = 0;
> +	obj[0].rsvd1 = 0;
> +	obj[0].rsvd2 = 0;
> +
> +	obj[1].handle = src;
> +	obj[1].relocation_count = 0;
> +	obj[1].relocs_ptr = 0;
> +	obj[1].alignment = 0;
> +	obj[1].offset = 0;
> +	obj[1].flags = 0;
> +	obj[1].rsvd1 = 0;
> +	obj[1].rsvd2 = 0;
> +
> +	obj[2].handle = handle;
> +	obj[2].relocation_count = 2;
> +	obj[2].relocs_ptr = (uintptr_t)reloc;
> +	obj[2].alignment = 0;
> +	obj[2].offset = 0;
> +	obj[2].flags = 0;
> +	obj[2].rsvd1 = obj[2].rsvd2 = 0;
> +
> +	exec.buffers_ptr = (uintptr_t)obj;
> +	exec.buffer_count = 3;
> +	exec.batch_start_offset = 0;
> +	exec.batch_len = i * 4;
> +	exec.DR1 = exec.DR4 = 0;
> +	exec.num_cliprects = 0;
> +	exec.cliprects_ptr = 0;
> +	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
> +	i915_execbuffer2_set_context_id(exec, 0);
> +	exec.rsvd2 = 0;
> +
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> +	if (ret)
> +		ret = errno;
> +
> +	if (error == ~0)
> +		igt_assert(ret != 0);
> +	else
> +		igt_assert(ret == error);
> +
> +	gem_close(fd, handle);
> +}
> +
> +static void
> +blit(int fd, uint32_t dst, uint32_t src, uint32_t *all_bo, int n_bo, int error)
> +{
> +	uint32_t batch[12];
> +	struct drm_i915_gem_relocation_entry reloc[2];
> +	struct drm_i915_gem_exec_object2 *obj;
> +	struct drm_i915_gem_execbuffer2 exec;
> +	uint32_t handle;
> +	int n, ret, i=0;
> +
> +	batch[i++] = XY_SRC_COPY_BLT_CMD |
> +		  XY_SRC_COPY_BLT_WRITE_ALPHA |
> +		  XY_SRC_COPY_BLT_WRITE_RGB;
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i - 1] |= 8;
> +	else
> +		batch[i - 1] |= 6;
> +	batch[i++] = (3 << 24) | /* 32 bits */
> +		  (0xcc << 16) | /* copy ROP */
> +		  WIDTH*4;
> +	batch[i++] = 0; /* dst x1,y1 */
> +	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
> +	batch[i++] = 0; /* dst reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = 0; /* src x1,y1 */
> +	batch[i++] = WIDTH*4;
> +	batch[i++] = 0; /* src reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = MI_BATCH_BUFFER_END;
> +	batch[i++] = MI_NOOP;
> +
> +	handle = gem_create(fd, 4096);
> +	gem_write(fd, handle, 0, batch, sizeof(batch));
> +
> +	reloc[0].target_handle = dst;
> +	reloc[0].delta = 0;
> +	reloc[0].offset = 4 * sizeof(batch[0]);
> +	reloc[0].presumed_offset = 0;
> +	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
> +	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
> +
> +	reloc[1].target_handle = src;
> +	reloc[1].delta = 0;
> +	reloc[1].offset = 7 * sizeof(batch[0]);
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		reloc[1].offset += sizeof(batch[0]);
> +	reloc[1].presumed_offset = 0;
> +	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
> +	reloc[1].write_domain = 0;
> +
> +	obj = calloc(n_bo + 1, sizeof(*obj));
> +	for (n = 0; n < n_bo; n++)
> +		obj[n].handle = all_bo[n];
> +	obj[n].handle = handle;
> +	obj[n].relocation_count = 2;
> +	obj[n].relocs_ptr = (uintptr_t)reloc;
> +
> +	exec.buffers_ptr = (uintptr_t)obj;
> +	exec.buffer_count = n_bo + 1;
> +	exec.batch_start_offset = 0;
> +	exec.batch_len = i * 4;
> +	exec.DR1 = exec.DR4 = 0;
> +	exec.num_cliprects = 0;
> +	exec.cliprects_ptr = 0;
> +	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
> +	i915_execbuffer2_set_context_id(exec, 0);
> +	exec.rsvd2 = 0;
> +
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> +	if (ret)
> +		ret = errno;
> +
> +	igt_assert(ret == error);
> +
> +	gem_close(fd, handle);
> +	free(obj);
> +}
> +
> +static uint32_t
> +create_userptr(int fd, uint32_t val, uint32_t *ptr)
> +{
> +	uint32_t handle;
> +	int i, ret;
> +
> +	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
> +	igt_assert(ret == 0);
> +	igt_assert(handle != 0);
> +
> +	/* Fill the BO with dwords starting at val */
> +	for (i = 0; i < WIDTH*HEIGHT; i++)
> +		ptr[i] = val++;
> +
> +	return handle;
> +}
> +
> +static void **handle_ptr_map;
> +static unsigned int num_handle_ptr_map;
> +
> +static void add_handle_ptr(uint32_t handle, void *ptr)
> +{
> +	if (handle >= num_handle_ptr_map) {
> +		handle_ptr_map = realloc(handle_ptr_map,
> +					 (handle + 1000) * sizeof(void*));
> +		num_handle_ptr_map = handle + 1000;
> +	}
> +
> +	handle_ptr_map[handle] = ptr;
> +}
> +
> +static void *get_handle_ptr(uint32_t handle)
> +{
> +	return handle_ptr_map[handle];
> +}
> +
> +static void free_handle_ptr(uint32_t handle)
> +{
> +	igt_assert(handle < num_handle_ptr_map);
> +	igt_assert(handle_ptr_map[handle]);
> +
> +	free(handle_ptr_map[handle]);
> +	handle_ptr_map[handle] = NULL;
> +}
> +
> +static uint32_t create_userptr_bo(int fd, int size)
> +{
> +	void *ptr;
> +	uint32_t handle;
> +	int ret;
> +
> +	ret = posix_memalign(&ptr, PAGE_SIZE, size);
> +	igt_assert(ret == 0);
> +
> +	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
> +	igt_assert(ret == 0);
> +	add_handle_ptr(handle, ptr);
> +
> +	return handle;
> +}
> +
> +static void clear(int fd, uint32_t handle, int size)
> +{
> +	void *ptr = get_handle_ptr(handle);
> +
> +	igt_assert(ptr != NULL);
> +
> +	memset(ptr, 0, size);
> +}
> +
> +static void free_userptr_bo(int fd, uint32_t handle)
> +{
> +	gem_close(fd, handle);
> +	free_handle_ptr(handle);
> +}
> +
> +static uint32_t
> +create_bo(int fd, uint32_t val)
> +{
> +	uint32_t handle;
> +	int i;
> +
> +	handle = gem_create(fd, sizeof(linear));
> +
> +	/* Fill the BO with dwords starting at val */
> +	for (i = 0; i < WIDTH*HEIGHT; i++)
> +		linear[i] = val++;
> +	gem_write(fd, handle, 0, linear, sizeof(linear));
> +
> +	return handle;
> +}
> +
> +static void
> +check_cpu(uint32_t *ptr, uint32_t val)
> +{
> +	int i;
> +
> +	for (i = 0; i < WIDTH*HEIGHT; i++) {
> +		if (ptr[i] != val) {
> +			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
> +				"at offset 0x%08x\n",
> +				val, ptr[i], i * 4);
> +			abort();
> +		}
> +		val++;
> +	}
> +}
> +
> +static void
> +check_gpu(int fd, uint32_t handle, uint32_t val)
> +{
> +	gem_read(fd, handle, 0, linear, sizeof(linear));
> +	check_cpu(linear, val);
> +}
> +
> +static int has_userptr(int fd)
> +{
> +	uint32_t handle = 0;
> +	void *ptr;
> +	uint32_t oldflags;
> +	int ret;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +	oldflags = userptr_flags;
> +	gem_userptr_test_unsynchronized();
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	userptr_flags = oldflags;
> +	if (ret != 0) {
> +		free(ptr);
> +		return 0;
> +	}
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return handle != 0;
> +}
> +
> +static int test_input_checking(int fd)
> +{
> +	struct local_i915_gem_userptr userptr;
> +	int ret;
> +
> +	/* Invalid flags. */
> +	userptr.user_ptr = 0;
> +	userptr.user_size = 0;
> +	userptr.flags = ~0;
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	igt_assert(ret != 0);
> +
> +	/* Too big. */
> +	userptr.user_ptr = 0;
> +	userptr.user_size = ~0;
> +	userptr.flags = 0;
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	igt_assert(ret != 0);
> +
> +	/* Both wrong. */
> +	userptr.user_ptr = 0;
> +	userptr.user_size = ~0;
> +	userptr.flags = ~0;
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	igt_assert(ret != 0);
> +
> +	return 0;
> +}
> +
> +static int test_access_control(int fd)
> +{
> +	igt_fork(child, 1) {
> +		void *ptr;
> +		int ret;
> +		uint32_t handle;
> +
> +		igt_drop_root();
> +
> +		/* CAP_SYS_ADMIN is needed for UNSYNCHRONIZED mappings. */
> +		gem_userptr_test_unsynchronized();
> +
> +		igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +
> +		ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +		if (ret == 0)
> +			gem_close(fd, handle);
> +		free(ptr);
> +		igt_assert(ret == EPERM);
> +	}
> +
> +	igt_waitchildren();
> +
> +	return 0;
> +}
> +
> +static int test_invalid_mapping(int fd)
> +{
> +	int ret;
> +	uint32_t handle, handle2;
> +	void *ptr;
> +
> +	/* NULL pointer. */
> +	ret = gem_userptr(fd, NULL, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
> +	gem_close(fd, handle);
> +
> +	/* GTT mapping */
> +	handle = create_bo(fd, 0);
> +	ptr = gem_mmap__gtt(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
> +	if (ptr == NULL)
> +		gem_close(fd, handle);
> +	assert(ptr != NULL);
> +	assert(((unsigned long)ptr & (PAGE_SIZE - 1)) == 0);
> +	assert((sizeof(linear) & (PAGE_SIZE - 1)) == 0);
> +	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle2);
> +	igt_assert(ret == 0);
> +	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
> +	gem_close(fd, handle2);
> +	munmap(ptr, sizeof(linear));
> +	gem_close(fd, handle);
> +
> +	return 0;
> +}
> +
> +static int test_forbidden_ops(int fd)
> +{
> +	void *ptr;
> +	int ret;
> +	uint32_t handle;
> +	char buf[PAGE_SIZE];
> +	struct drm_i915_gem_pread gem_pread;
> +	struct drm_i915_gem_pwrite gem_pwrite;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +
> +	gem_pread.handle = handle;
> +	gem_pread.offset = 0;
> +	gem_pread.size = PAGE_SIZE;
> +	gem_pread.data_ptr = (uintptr_t)buf;
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
> +	if (ret == 0) {
> +		gem_close(fd, handle);
> +		free(ptr);
> +	}
> +	igt_assert(ret != 0);
> +
> +	gem_pwrite.handle = handle;
> +	gem_pwrite.offset = 0;
> +	gem_pwrite.size = PAGE_SIZE;
> +	gem_pwrite.data_ptr = (uintptr_t)buf;
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
> +	if (ret == 0) {
> +		gem_close(fd, handle);
> +		free(ptr);
> +	}
> +	igt_assert(ret != 0);
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static char counter;
> +
> +static void (*orig_sigbus)(int sig, siginfo_t *info, void *param);
> +static unsigned long sigbus_start;
> +static long sigbus_cnt = -1;
> +
> +static void
> +check_bo(int fd1, uint32_t handle1, int is_userptr, int fd2, uint32_t handle2)
> +{
> +	char *ptr1, *ptr2;
> +	int i;
> +	unsigned long size = sizeof(linear);
> +
> +	if (is_userptr)
> +		ptr1 = get_handle_ptr(handle1);
> +	else
> +		ptr1 = gem_mmap(fd1, handle1, sizeof(linear), PROT_READ | PROT_WRITE);
> +
> +	ptr2 = gem_mmap(fd2, handle2, sizeof(linear), PROT_READ | PROT_WRITE);
> +
> +	igt_assert(ptr1);
> +	igt_assert(ptr2);
> +
> +	sigbus_start = (unsigned long)ptr2;
> +
> +	if (sigbus_cnt == 0)
> +		size = 1;
> +
> +	/* check whether it's still our old object first. */
> +	for (i = 0; i < size; i++) {
> +		igt_assert(ptr1[i] == counter);
> +		igt_assert(ptr2[i] == counter);
> +	}
> +
> +	counter++;
> +
> +	if (size > 1) {
> +		memset(ptr1, counter, size);
> +		igt_assert(memcmp(ptr1, ptr2, size) == 0);
> +	}
> +
> +	if (!is_userptr)
> +		munmap(ptr1, sizeof(linear));
> +	munmap(ptr2, sizeof(linear));
> +}
> +
> +static int export_handle(int fd, uint32_t handle, int *outfd)
> +{
> +	struct drm_prime_handle args;
> +	int ret;
> +
> +	args.handle = handle;
> +	args.flags = DRM_CLOEXEC;
> +	args.fd = -1;
> +
> +	ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
> +	if (ret)
> +		ret = errno;
> +	*outfd = args.fd;
> +
> +	return ret;
> +}
> +
> +static void sigbus(int sig, siginfo_t *info, void *param)
> +{
> +	unsigned long ptr = (unsigned long)info->si_addr;
> +	void *addr;
> +
> +	if (ptr >= sigbus_start &&
> +	    ptr <= (sigbus_start + sizeof(linear))) {
> +		sigbus_cnt++;
> +		addr = mmap((void *)ptr, sizeof(linear), PROT_READ | PROT_WRITE,
> +				MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
> +		if ((unsigned long)addr == ptr) {
> +			memset(addr, counter, sizeof(linear));
> +			return;
> +		}
> +	}
> +
> +	if (orig_sigbus)
> +		orig_sigbus(sig, info, param);
> +	assert(0);
> +}
> +
> +static int test_dmabuf(void)
> +{
> +	int fd1, fd2;
> +	uint32_t handle, handle_import1, handle_import2, handle_selfimport;
> +	int dma_buf_fd = -1;
> +	int ret;
> +	struct sigaction sigact, orig_sigact;
> +
> +	fd1 = drm_open_any();
> +	fd2 = drm_open_any();
> +
> +	handle = create_userptr_bo(fd1, sizeof(linear));
> +
> +	ret = export_handle(fd1, handle, &dma_buf_fd);
> +	if (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) {
> +		igt_assert(ret == EINVAL);
> +		free_userptr_bo(fd1, handle);
> +
> +		return 0;
> +	} else {
> +		igt_assert(ret == 0);
> +		igt_assert(dma_buf_fd >= 0);
> +	}
> +	handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd);
> +	check_bo(fd1, handle, 1, fd2, handle_import1);
> +
> +	/* reimport should give us the same handle so that userspace can check
> +	 * whether it has that bo already somewhere. */
> +	handle_import2 = prime_fd_to_handle(fd2, dma_buf_fd);
> +	igt_assert(handle_import1 == handle_import2);
> +
> +	/* Same for re-importing on the exporting fd. */
> +	handle_selfimport = prime_fd_to_handle(fd1, dma_buf_fd);
> +	igt_assert(handle == handle_selfimport);
> +
> +	/* close dma_buf, check whether nothing disappears. */
> +	close(dma_buf_fd);
> +	check_bo(fd1, handle, 1, fd2, handle_import1);
> +
> +	/* destroy userptr object and expect SIGBUS */
> +	free_userptr_bo(fd1, handle);
> +	sigact.sa_sigaction = sigbus;
> +	sigact.sa_flags = SA_SIGINFO;
> +	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
> +	assert(ret == 0);
> +	orig_sigbus = orig_sigact.sa_sigaction;
> +	sigbus_cnt = 0;
> +	check_bo(fd2, handle_import1, 0, fd2, handle_import1);
> +	assert(sigbus_cnt > 0);
> +	sigact.sa_sigaction = orig_sigbus;
> +	sigact.sa_flags = SA_SIGINFO;
> +	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
> +	assert(ret == 0);
> +
> +	gem_close(fd2, handle_import1);
> +	close(fd1);
> +	close(fd2);
> +
> +	return 0;
> +}
> +
> +static int test_usage_restrictions(int fd)
> +{
> +	void *ptr;
> +	int ret;
> +	uint32_t handle;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE * 2) == 0);
> +
> +	/* Address not aligned. */
> +	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret != 0);
> +
> +	/* Size not rounded to page size. */
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE - 1, 0, &handle);
> +	igt_assert(ret != 0);
> +
> +	/* Both wrong. */
> +	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE - 1, 0, &handle);
> +	igt_assert(ret != 0);
> +
> +	/* Read-only not supported. */
> +	ret = gem_userptr(fd, (char *)ptr, PAGE_SIZE, 1, &handle);
> +	igt_assert(ret != 0);
> +
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static int test_create_destroy(int fd)
> +{
> +	void *ptr;
> +	int ret;
> +	uint32_t handle;
> +
> +	igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static int test_coherency(int fd, int count)
> +{
> +	uint32_t *memory;
> +	uint32_t *cpu, *cpu_val;
> +	uint32_t *gpu, *gpu_val;
> +	uint32_t start = 0;
> +	int i, ret;
> +
> +	printf("Using 2x%d 1MiB buffers\n", count);
> +
> +	ret = posix_memalign((void **)&memory, PAGE_SIZE, count*sizeof(linear));
> +	if (ret != 0 || memory == NULL) {
> +		fprintf(stderr, "Unable to allocate %lld bytes\n",
> +			(long long)count*sizeof(linear));
> +		return 1;
> +	}
> +
> +	gpu = malloc(sizeof(uint32_t)*count*4);
> +	gpu_val = gpu + count;
> +	cpu = gpu_val + count;
> +	cpu_val = cpu + count;
> +
> +	for (i = 0; i < count; i++) {
> +		gpu[i] = create_bo(fd, start);
> +		gpu_val[i] = start;
> +		start += WIDTH*HEIGHT;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		cpu[i] = create_userptr(fd, start, memory+i*WIDTH*HEIGHT);
> +		cpu_val[i] = start;
> +		start += WIDTH*HEIGHT;
> +	}
> +
> +	printf("Verifying initialisation...\n");
> +	for (i = 0; i < count; i++) {
> +		check_gpu(fd, gpu[i], gpu_val[i]);
> +		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> +	}
> +
> +	printf("Cyclic blits cpu->gpu, forward...\n");
> +	for (i = 0; i < count * 4; i++) {
> +		int src = i % count;
> +		int dst = (i + 1) % count;
> +
> +		copy(fd, gpu[dst], cpu[src], 0);
> +		gpu_val[dst] = cpu_val[src];
> +	}
> +	for (i = 0; i < count; i++)
> +		check_gpu(fd, gpu[i], gpu_val[i]);
> +
> +	printf("Cyclic blits gpu->cpu, backward...\n");
> +	for (i = 0; i < count * 4; i++) {
> +		int src = (i + 1) % count;
> +		int dst = i % count;
> +
> +		copy(fd, cpu[dst], gpu[src], 0);
> +		cpu_val[dst] = gpu_val[src];
> +	}
> +	for (i = 0; i < count; i++) {
> +		gem_userptr_sync(fd, cpu[i]);
> +		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> +	}
> +
> +	printf("Random blits...\n");
> +	for (i = 0; i < count * 4; i++) {
> +		int src = random() % count;
> +		int dst = random() % count;
> +
> +		if (random() & 1) {
> +			copy(fd, gpu[dst], cpu[src], 0);
> +			gpu_val[dst] = cpu_val[src];
> +		} else {
> +			copy(fd, cpu[dst], gpu[src], 0);
> +			cpu_val[dst] = gpu_val[src];
> +		}
> +	}
> +	for (i = 0; i < count; i++) {
> +		check_gpu(fd, gpu[i], gpu_val[i]);
> +		gem_close(fd, gpu[i]);
> +
> +		gem_userptr_sync(fd, cpu[i]);
> +		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> +		gem_close(fd, cpu[i]);
> +	}
> +
> +	free(gpu);
> +	free(memory);
> +
> +	return 0;
> +}
> +
> +static struct igt_eviction_test_ops fault_ops = {
> +	.create = create_userptr_bo,
> +	.close = free_userptr_bo,
> +	.copy = blit,
> +	.clear = clear,
> +};
> +
> +static int can_swap(void)
> +{
> +	unsigned long as, ram;
> +
> +	/* Cannot swap if not enough address space */
> +
> +	/* FIXME: Improve check criteria. */
> +	if (sizeof(void*) < 8)
> +		as = 3 * 1024;
> +	else
> +		as = 256 * 1024; /* Just a big number */
> +
> +	ram = intel_get_total_ram_mb();
> +
> +	if ((as - 128) < (ram - 256))
> +		return 0;
> +
> +	return 1;
> +}
> +
> +#define min(a, b) ((a) < (b) ? (a) : (b))
> +
> +static void test_forking_evictions(int fd, int size, int count,
> +			     unsigned flags)
> +{
> +	int trash_count;
> +	int num_threads;
> +
> +	trash_count = intel_get_total_ram_mb() * 11 / 10;
> +	/* Use the fact test will spawn a number of child
> +	 * processes meaning swapping will be triggered system
> +	 * wide even if one process on it's own can't do it.
> +	 */
> +	num_threads = min(sysconf(_SC_NPROCESSORS_ONLN) * 4, 12);
> +	trash_count /= num_threads;
> +	if (count > trash_count)
> +		count = trash_count;
> +
> +	forking_evictions(fd, &fault_ops, size, count, trash_count, flags);
> +}
> +
> +static void test_swapping_evictions(int fd, int size, int count)
> +{
> +	int trash_count;
> +
> +	igt_skip_on_f(!can_swap(),
> +		"Not enough process address space for swapping tests.\n");
> +
> +	trash_count = intel_get_total_ram_mb() * 11 / 10;
> +
> +	swapping_evictions(fd, &fault_ops, size, count, trash_count);
> +}
> +
> +static void test_minor_evictions(int fd, int size, int count)
> +{
> +	minor_evictions(fd, &fault_ops, size, count);
> +}
> +
> +static void test_major_evictions(int fd, int size, int count)
> +{
> +	major_evictions(fd, &fault_ops, size, count);
> +}
> +
> +static int test_overlap(int fd, int expected)
> +{
> +	char *ptr;
> +	int ret;
> +	uint32_t handle, handle2;
> +
> +	igt_assert(posix_memalign((void *)&ptr, PAGE_SIZE, PAGE_SIZE * 3) == 0);
> +
> +	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle2);
> +	igt_assert(ret == 0);
> +	gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr + PAGE_SIZE * 2, PAGE_SIZE, 0, &handle2);
> +	igt_assert(ret == 0);
> +	gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE * 2, 0, &handle2);
> +	igt_assert(ret == expected);
> +	if (ret == 0)
> +		gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE * 2, 0, &handle2);
> +	igt_assert(ret == expected);
> +	if (ret == 0)
> +		gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE * 3, 0, &handle2);
> +	igt_assert(ret == expected);
> +	if (ret == 0)
> +		gem_close(fd, handle2);
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static int test_unmap(int fd, int expected)
> +{
> +	char *ptr, *bo_ptr;
> +	const unsigned int num_obj = 3;
> +	unsigned int i;
> +	uint32_t bo[num_obj + 1];
> +	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
> +	int ret;
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
> +						& ~(PAGE_SIZE - 1));
> +
> +	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
> +		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
> +		igt_assert(ret == 0);
> +	}
> +
> +	bo[num_obj] = create_bo(fd, 0);
> +
> +	for (i = 0; i < num_obj; i++)
> +		copy(fd, bo[num_obj], bo[i], 0);
> +
> +	ret = munmap(ptr, map_size);
> +	assert(ret == 0);
> +
> +	for (i = 0; i < num_obj; i++)
> +		copy(fd, bo[num_obj], bo[i], expected);
> +
> +	for (i = 0; i < (num_obj + 1); i++)
> +		gem_close(fd, bo[i]);
> +
> +	return 0;
> +}
> +
> +static int test_unmap_after_close(int fd)
> +{
> +	char *ptr, *bo_ptr;
> +	const unsigned int num_obj = 3;
> +	unsigned int i;
> +	uint32_t bo[num_obj + 1];
> +	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
> +	int ret;
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
> +						& ~(PAGE_SIZE - 1));
> +
> +	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
> +		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
> +		igt_assert(ret == 0);
> +	}
> +
> +	bo[num_obj] = create_bo(fd, 0);
> +
> +	for (i = 0; i < num_obj; i++)
> +		copy(fd, bo[num_obj], bo[i], 0);
> +
> +	for (i = 0; i < (num_obj + 1); i++)
> +		gem_close(fd, bo[i]);
> +
> +	ret = munmap(ptr, map_size);
> +	assert(ret == 0);
> +
> +	return 0;
> +}
> +
> +static int test_unmap_cycles(int fd, int expected)
> +{
> +	int i;
> +
> +	for (i = 0; i < 1000; i++)
> +		test_unmap(fd, expected);
> +
> +	return 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	uint64_t aperture_size;
> +	unsigned int total_ram;
> +	int fd = -1, count = 0, size = 0, ret;
> +
> +	igt_skip_on_simulation();
> +
> +	igt_subtest_init(argc, argv);
> +
> +	igt_fixture {
> +		fd = drm_open_any();
> +		igt_assert(fd >= 0);
> +
> +		ret = has_userptr(fd);
> +		igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
> +			      strerror(errno), ret);
> +
> +		size = sizeof(linear);
> +
> +		aperture_size = gem_aperture_size(fd);
> +		printf("Aperture size is %lu MiB\n", (long)(aperture_size / (1024*1024)));
> +
> +		if (argc > 1)
> +			count = atoi(argv[1]);
> +		if (count == 0)
> +			count = 2 * aperture_size / (1024*1024) / 3;
> +
> +		total_ram = intel_get_total_ram_mb();
> +		printf("Total RAM is %u MiB\n", total_ram);
> +
> +		if (count > total_ram * 3 / 4) {
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +			printf("Not enough RAM to run test, reducing buffer count.\n");
> +		}
> +	}
> +
> +	igt_subtest("input-checking")
> +		test_input_checking(fd);
> +
> +	igt_subtest("usage-restrictions")
> +		test_usage_restrictions(fd);
> +
> +	igt_subtest("invalid-mapping")
> +		test_invalid_mapping(fd);
> +
> +	igt_subtest("forbidden-operations")
> +		test_forbidden_ops(fd);
> +
> +	printf("Testing unsynchronized mappings...\n");
> +	gem_userptr_test_unsynchronized();
> +
> +	igt_subtest("create-destroy-unsync")
> +		test_create_destroy(fd);
> +
> +	igt_subtest("unsync-overlap")
> +		test_overlap(fd, 0);
> +
> +	igt_subtest("unsync-unmap")
> +		test_unmap(fd, 0);
> +
> +	igt_subtest("unsync-unmap-cycles")
> +		test_unmap_cycles(fd, 0);
> +
> +	igt_subtest("unsync-unmap-after-close")
> +		test_unmap_after_close(fd);
> +
> +	igt_subtest("coherency-unsync")
> +		test_coherency(fd, count);
> +
> +	igt_subtest("dmabuf-unsync")
> +		test_dmabuf();
> +
> +	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
> +		igt_subtest_f("forked-unsync%s%s%s-%s",
> +		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
> +		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
> +		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
> +				"-mempressure" : "",
> +		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
> +				"interruptible" : "normal") {
> +			test_forking_evictions(fd, size, count, flags);
> +		}
> +	}
> +
> +	igt_subtest("swapping-unsync-normal")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-unsync-normal")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-unsync-normal") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_fixture {
> +		size = sizeof(linear);
> +		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
> +		if (count > total_ram * 3 / 4)
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +	}
> +
> +	igt_fork_signal_helper();
> +
> +	igt_subtest("swapping-unsync-interruptible")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-unsync-interruptible")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-unsync-interruptible") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_stop_signal_helper();
> +
> +	printf("Testing synchronized mappings...\n");
> +
> +	igt_fixture {
> +		size = sizeof(linear);
> +		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
> +		if (count > total_ram * 3 / 4)
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +	}
> +
> +	gem_userptr_test_synchronized();
> +
> +	igt_subtest("create-destroy-sync")
> +		test_create_destroy(fd);
> +
> +	igt_subtest("sync-overlap")
> +		test_overlap(fd, EINVAL);
> +
> +	igt_subtest("sync-unmap")
> +		test_unmap(fd, EFAULT);
> +
> +	igt_subtest("sync-unmap-cycles")
> +		test_unmap_cycles(fd, EFAULT);
> +
> +	igt_subtest("sync-unmap-after-close")
> +		test_unmap_after_close(fd);
> +
> +	igt_subtest("coherency-sync")
> +		test_coherency(fd, count);
> +
> +	igt_subtest("dmabuf-sync")
> +		test_dmabuf();
> +
> +	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
> +		igt_subtest_f("forked-sync%s%s%s-%s",
> +		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
> +		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
> +		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
> +				"-mempressure" : "",
> +		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
> +				"interruptible" : "normal") {
> +			test_forking_evictions(fd, size, count, flags);
> +		}
> +	}
> +
> +	igt_subtest("swapping-normal-sync")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-normal-sync")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-normal-sync") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_fixture {
> +		size = 1024 * 1024;
> +		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
> +		if (count > total_ram * 3 / 4)
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +	}
> +
> +	igt_fork_signal_helper();
> +
> +	igt_subtest("swapping-sync-interruptible")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-sync-interruptible")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-sync-interruptible") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_stop_signal_helper();
> +
> +	igt_subtest("access-control")
> +	test_access_control(fd);
> +
> +	igt_exit();
> +
> +	return 0;
> +}
> -- 
> 1.9.0
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-04-17 23:18     ` Volkin, Bradley D
@ 2014-04-22 18:59       ` Daniel Vetter
  2014-04-23 13:28       ` Tvrtko Ursulin
  1 sibling, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-04-22 18:59 UTC (permalink / raw)
  To: Volkin, Bradley D; +Cc: Intel-gfx

On Thu, Apr 17, 2014 at 04:18:46PM -0700, Volkin, Bradley D wrote:
> On Wed, Mar 19, 2014 at 04:13:06AM -0700, Tvrtko Ursulin wrote:
> > +	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
> > +					& ~(PAGE_SIZE - 1));
> 
> You might add an ALIGN macro in this file or a suitable header. A couple of
> .c files in lib/ individually define one already.

lib/drmtest.h (with the gtkdoc for it include) is the current grab-bag for
such random useful pieces. We already have an ARRAY_SIZE in there.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-04-17 23:18     ` Volkin, Bradley D
  2014-04-22 18:59       ` Daniel Vetter
@ 2014-04-23 13:28       ` Tvrtko Ursulin
  2014-04-23 15:24         ` Volkin, Bradley D
  1 sibling, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-04-23 13:28 UTC (permalink / raw)
  To: Volkin, Bradley D; +Cc: Intel-gfx


Hi Brad,

On 04/18/2014 12:18 AM, Volkin, Bradley D wrote:
> On Wed, Mar 19, 2014 at 04:13:06AM -0700, Tvrtko Ursulin wrote:
>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>
>> This adds a small benchmark for the new userptr functionality.
>>
>> Apart from basic surface creation and destruction, also tested is the
>> impact of having userptr surfaces in the process address space. Reason
>> for that is the impact of MMU notifiers on common address space
>> operations like munmap() which is per process.
>>
>> v2:
>>    * Moved to benchmarks.
>>    * Added pointer read/write tests.
>>    * Changed output to say iterations per second instead of
>>      operations per second.
>>    * Multiply result by batch size for multi-create* tests
>>      for a more comparable number with create-destroy test.
>>
>> v3:
>>    * Fixed ioctl detection on kernels without MMU_NOTIFIERs.
>>
>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>> Cc: Chris Wilson <chris@chris-wilson.co.uk>
>> ---
>>   Android.mk                         |   3 +-
>>   benchmarks/.gitignore              |   1 +
>>   benchmarks/Android.mk              |  36 +++
>>   benchmarks/Makefile.am             |   7 +-
>>   benchmarks/Makefile.sources        |   6 +
>>   benchmarks/gem_userptr_benchmark.c | 513 +++++++++++++++++++++++++++++++++++++
>>   6 files changed, 558 insertions(+), 8 deletions(-)
>>   create mode 100644 benchmarks/Android.mk
>>   create mode 100644 benchmarks/Makefile.sources
>>   create mode 100644 benchmarks/gem_userptr_benchmark.c
>>
>> diff --git a/Android.mk b/Android.mk
>> index 8aeb2d4..0c969b8 100644
>> --- a/Android.mk
>> +++ b/Android.mk
>> @@ -1,2 +1 @@
>> -include $(call all-named-subdir-makefiles, lib tests tools)
>> -
>> +include $(call all-named-subdir-makefiles, lib tests tools benchmarks)
>> diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
>> index ddea6f7..09e5bd8 100644
>> --- a/benchmarks/.gitignore
>> +++ b/benchmarks/.gitignore
>> @@ -1,3 +1,4 @@
>> +gem_userptr_benchmark
>>   intel_upload_blit_large
>>   intel_upload_blit_large_gtt
>>   intel_upload_blit_large_map
>> diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
>> new file mode 100644
>> index 0000000..5bb8ef5
>> --- /dev/null
>> +++ b/benchmarks/Android.mk
>> @@ -0,0 +1,36 @@
>> +LOCAL_PATH := $(call my-dir)
>> +
>> +include $(LOCAL_PATH)/Makefile.sources
>> +
>> +#================#
>> +
>> +define add_benchmark
>> +    include $(CLEAR_VARS)
>> +
>> +    LOCAL_SRC_FILES := $1.c
>> +
>> +    LOCAL_CFLAGS += -DHAVE_STRUCT_SYSINFO_TOTALRAM
>> +    LOCAL_CFLAGS += -DANDROID -UNDEBUG -include "check-ndebug.h"
>> +    LOCAL_CFLAGS += -std=c99
>> +    # FIXME: drop once Bionic correctly annotates "noreturn" on pthread_exit
>> +    LOCAL_CFLAGS += -Wno-error=return-type
>> +    # Excessive complaining for established cases. Rely on the Linux version warnings.
>> +    LOCAL_CFLAGS += -Wno-sign-compare
>> +
>> +    LOCAL_MODULE := $1
>> +    LOCAL_MODULE_TAGS := optional
>> +
>> +    LOCAL_STATIC_LIBRARIES := libintel_gpu_tools
>> +
>> +    LOCAL_SHARED_LIBRARIES := libpciaccess  \
>> +                              libdrm        \
>> +                              libdrm_intel
>> +
>> +    include $(BUILD_EXECUTABLE)
>> +endef
>> +
>> +#================#
>> +
>> +benchmark_list := $(bin_PROGRAMS)
>> +
>> +$(foreach item,$(benchmark_list),$(eval $(call add_benchmark,$(item))))
>> diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
>> index e2ad784..d173bf4 100644
>> --- a/benchmarks/Makefile.am
>> +++ b/benchmarks/Makefile.am
>> @@ -1,9 +1,4 @@
>> -
>> -bin_PROGRAMS = 				\
>> -	intel_upload_blit_large		\
>> -	intel_upload_blit_large_gtt	\
>> -	intel_upload_blit_large_map	\
>> -	intel_upload_blit_small
>> +include Makefile.sources
>>
>>   AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib
>>   AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) $(CAIRO_CFLAGS)
>> diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
>> new file mode 100644
>> index 0000000..fd6c107
>> --- /dev/null
>> +++ b/benchmarks/Makefile.sources
>> @@ -0,0 +1,6 @@
>> +bin_PROGRAMS =                          \
>> +        intel_upload_blit_large         \
>> +        intel_upload_blit_large_gtt     \
>> +        intel_upload_blit_large_map     \
>> +        intel_upload_blit_small         \
>> +        gem_userptr_benchmark
>
> You might split the makefile cleanup aspect of this into a separate
> patch, but I'm fine either way.

Good idea, will try to squeeze that in.

>> diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
>> new file mode 100644
>> index 0000000..218f6f1
>> --- /dev/null
>> +++ b/benchmarks/gem_userptr_benchmark.c
>> @@ -0,0 +1,513 @@
>> +/*
>> + * Copyright © 2014 Intel Corporation
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the next
>> + * paragraph) shall be included in all copies or substantial portions of the
>> + * Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> + * IN THE SOFTWARE.
>> + *
>> + * Authors:
>> + *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>> + *
>> + */
>> +
>> +/** @file gem_userptr_benchmark.c
>> + *
>> + * Benchmark the userptr code and impact of having userptr surfaces
>> + * in process address space on some normal operations.
>> + *
>> + */
>> +
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <fcntl.h>
>> +#include <inttypes.h>
>> +#include <errno.h>
>> +#include <sys/stat.h>
>> +#include <sys/time.h>
>> +#include <sys/mman.h>
>> +#include "drm.h"
>> +#include "i915_drm.h"
>> +#include "drmtest.h"
>> +#include "intel_bufmgr.h"
>> +#include "intel_batchbuffer.h"
>> +#include "intel_gpu_tools.h"
>> +
>> +#define WIDTH 128
>> +#define HEIGHT 128
>> +#define PAGE_SIZE 4096
>> +
>> +#define LOCAL_I915_GEM_USERPTR       0x34
>> +#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
>> +struct local_i915_gem_userptr {
>> +	uint64_t user_ptr;
>> +	uint64_t user_size;
>> +	uint32_t flags;
>> +#define I915_USERPTR_READ_ONLY (1<<0)
>> +#define I915_USERPTR_UNSYNCHRONIZED (1<<31)
>> +	uint32_t handle;
>> +};
>> +
>> +static uint32_t userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
>> +
>> +static uint32_t linear[WIDTH*HEIGHT];
>
> I may have missed it, but I don't think we use this variable except
> to do sizeof(linear). If that's the case, a constant for the buffer
> size might make the code more readable.

You're right, too much copy & paste.

>> +
>> +static void gem_userptr_test_unsynchronized(void)
>> +{
>> +	userptr_flags = I915_USERPTR_UNSYNCHRONIZED;
>> +}
>> +
>> +static void gem_userptr_test_synchronized(void)
>> +{
>> +	userptr_flags = 0;
>> +}
>> +
>> +static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
>> +{
>> +	struct local_i915_gem_userptr userptr;
>> +	int ret;
>> +
>> +	userptr.user_ptr = (uintptr_t)ptr;
>> +	userptr.user_size = size;
>> +	userptr.flags = userptr_flags;
>> +	if (read_only)
>> +		userptr.flags |= I915_USERPTR_READ_ONLY;
>> +
>> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
>> +	if (ret)
>> +		ret = errno;
>> +	igt_skip_on_f(ret == ENODEV &&
>> +		      (userptr_flags & I915_USERPTR_UNSYNCHRONIZED) == 0,
>> +		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
>> +	if (ret == 0)
>> +		*handle = userptr.handle;
>> +
>> +	return ret;
>> +}
>> +
>> +static uint32_t
>> +create_userptr(int fd, uint32_t val, uint32_t *ptr)
>> +{
>> +	uint32_t handle;
>> +	int i, ret;
>> +
>> +	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
>> +	igt_assert(ret == 0);
>> +	igt_assert(handle != 0);
>> +
>> +	/* Fill the BO with dwords starting at val */
>> +	for (i = 0; i < WIDTH*HEIGHT; i++)
>> +		ptr[i] = val++;
>> +
>> +	return handle;
>> +}
>
> I don't see that this function is used in this test.

You are right, artifact of this file starting from gem_userptr_blits.c 
and then removing stuff. Obviously not enough removed.

>> +
>> +static void **handle_ptr_map;
>> +static unsigned int num_handle_ptr_map;
>
> I'd prefer that we explicitly initialize at least num_handle_ptr_map.

To zero, why?

>> +
>> +static void add_handle_ptr(uint32_t handle, void *ptr)
>> +{
>> +	if (handle >= num_handle_ptr_map) {
>> +		handle_ptr_map = realloc(handle_ptr_map,
>> +					 (handle + 1000) * sizeof(void*));
>> +		num_handle_ptr_map = handle + 1000;
>> +	}
>> +
>> +	handle_ptr_map[handle] = ptr;
>> +}
>> +
>> +static void *get_handle_ptr(uint32_t handle)
>> +{
>> +	return handle_ptr_map[handle];
>> +}
>> +
>> +static void free_handle_ptr(uint32_t handle)
>> +{
>> +	igt_assert(handle < num_handle_ptr_map);
>> +	igt_assert(handle_ptr_map[handle]);
>> +
>> +	free(handle_ptr_map[handle]);
>> +	handle_ptr_map[handle] = NULL;
>> +}
>> +
>> +static uint32_t create_userptr_bo(int fd, int size)
>> +{
>> +	void *ptr;
>> +	uint32_t handle;
>> +	int ret;
>> +
>> +	ret = posix_memalign(&ptr, PAGE_SIZE, size);
>> +	igt_assert(ret == 0);
>> +
>> +	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
>> +	igt_assert(ret == 0);
>> +	add_handle_ptr(handle, ptr);
>> +
>> +	return handle;
>> +}
>> +
>> +static void free_userptr_bo(int fd, uint32_t handle)
>> +{
>> +	gem_close(fd, handle);
>> +	free_handle_ptr(handle);
>> +}
>> +
>> +static int has_userptr(int fd)
>> +{
>> +	uint32_t handle = 0;
>> +	void *ptr;
>> +	uint32_t oldflags;
>> +	int ret;
>> +
>> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
>> +	oldflags = userptr_flags;
>> +	gem_userptr_test_unsynchronized();
>> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
>> +	userptr_flags = oldflags;
>> +	if (ret != 0) {
>> +		free(ptr);
>> +		return 0;
>> +	}
>> +
>> +	gem_close(fd, handle);
>> +	free(ptr);
>> +
>> +	return handle != 0;
>> +}
>> +
>> +static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
>> +static const unsigned int test_duration_sec = 3;
>> +
>> +static volatile unsigned int run_test;
>> +
>> +static void alarm_handler(int sig)
>> +{
>> +	assert(run_test == 1);
>> +	run_test = 0;
>> +}
>> +
>> +static void start_test(unsigned int duration)
>> +{
>> +	run_test = 1;
>> +	if (duration == 0)
>> +		duration = test_duration_sec;
>> +	signal(SIGALRM, alarm_handler);
>> +	alarm(duration);
>> +}
>> +
>> +static void exchange_ptr(void *array, unsigned i, unsigned j)
>> +{
>> +	void **arr, *tmp;
>> +	arr = (void **)array;
>> +
>> +	tmp = arr[i];
>> +	arr[i] = arr[j];
>> +	arr[j] = tmp;
>> +}
>> +
>> +static void test_malloc_free(int random)
>> +{
>> +	unsigned long iter = 0;
>> +	unsigned int i, tot = 1000;
>> +	void *ptr[tot];
>> +
>> +	start_test(test_duration_sec);
>> +
>> +	while (run_test) {
>> +		for (i = 0; i < tot; i++) {
>> +			ptr[i] = malloc(1000);
>> +			assert(ptr[i]);
>> +		}
>> +		if (random)
>> +			igt_permute_array(ptr, tot, exchange_ptr);
>> +		for (i = 0; i < tot; i++)
>> +			free(ptr[i]);
>> +		iter++;
>> +	}
>> +
>> +	printf("%8lu iter/s\n", iter / test_duration_sec);
>> +}
>> +
>> +static void test_malloc_realloc_free(int random)
>> +{
>> +	unsigned long iter = 0;
>> +	unsigned int i, tot = 1000;
>> +	void *ptr[tot];
>> +
>> +	start_test(test_duration_sec);
>> +
>> +	while (run_test) {
>> +		for (i = 0; i < tot; i++) {
>> +			ptr[i] = malloc(1000);
>> +			assert(ptr[i]);
>> +		}
>> +		if (random)
>> +			igt_permute_array(ptr, tot, exchange_ptr);
>> +		for (i = 0; i < tot; i++) {
>> +			ptr[i] = realloc(ptr[i], 2000);
>> +			assert(ptr[i]);
>> +		}
>> +		if (random)
>> +			igt_permute_array(ptr, tot, exchange_ptr);
>> +		for (i = 0; i < tot; i++)
>> +			free(ptr[i]);
>> +		iter++;
>> +	}
>> +
>> +	printf("%8lu iter/s\n", iter / test_duration_sec);
>> +}
>> +
>> +static void test_mmap_unmap(int random)
>> +{
>> +	unsigned long iter = 0;
>> +	unsigned int i, tot = 1000;
>> +	void *ptr[tot];
>> +
>> +	start_test(test_duration_sec);
>> +
>> +	while (run_test) {
>> +		for (i = 0; i < tot; i++) {
>> +			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
>> +					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
>> +			assert(ptr[i] != MAP_FAILED);
>> +		}
>> +		if (random)
>> +			igt_permute_array(ptr, tot, exchange_ptr);
>> +		for (i = 0; i < tot; i++)
>> +			munmap(ptr[i], 1000);
>> +		iter++;
>> +	}
>> +
>> +	printf("%8lu iter/s\n", iter / test_duration_sec);
>> +}
>> +
>> +static void test_ptr_read(void *ptr)
>> +{
>> +	unsigned long iter = 0;
>> +	volatile unsigned long *p;
>> +	unsigned long i, loops;
>> +	register unsigned long v;
>> +
>> +	loops = sizeof(linear) / sizeof(unsigned long) / 4;
>> +
>> +	start_test(test_duration_sec);
>> +
>> +	while (run_test) {
>> +		p = (unsigned long *)ptr;
>> +		for (i = 0; i < loops; i++) {
>> +			v = *p++;
>> +			v = *p++;
>> +			v = *p++;
>> +			v = *p++;
>> +		}
>> +		iter++;
>> +	}
>> +
>> +	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
>> +}
>> +
>> +static void test_ptr_write(void *ptr)
>> +{
>> +	unsigned long iter = 0;
>> +	volatile unsigned long *p;
>> +	register unsigned long i, loops;
>> +
>> +	loops = sizeof(linear) / sizeof(unsigned long) / 4;
>> +
>> +	start_test(test_duration_sec);
>> +
>> +	while (run_test) {
>> +		p = (unsigned long *)ptr;
>> +		for (i = 0; i < loops; i++) {
>> +			*p++ = i;
>> +			*p++ = i;
>> +			*p++ = i;
>> +			*p++ = i;
>> +		}
>> +		iter++;
>> +	}
>> +
>> +	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
>> +}
>> +
>> +static void test_impact(int fd)
>> +{
>> +	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
>> +	unsigned int subtest, i;
>> +	uint32_t handles[nr_bos[total-1]];
>> +	void *ptr;
>> +	char buffer[sizeof(linear)];
>> +
>> +	for (subtest = 0; subtest < total; subtest++) {
>> +		for (i = 0; i < nr_bos[subtest]; i++)
>> +			handles[i] = create_userptr_bo(fd, sizeof(linear));
>> +
>> +		if (nr_bos[subtest] > 0)
>> +			ptr = get_handle_ptr(handles[0]);
>> +		else
>> +			ptr = buffer;
>> +
>> +		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
>> +		test_ptr_read(ptr);
>> +
>> +		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
>> +		test_ptr_write(ptr);
>> +
>> +		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
>> +		test_malloc_free(0);
>> +		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
>> +		test_malloc_free(1);
>> +
>> +		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
>> +		test_malloc_realloc_free(0);
>> +		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
>> +		test_malloc_realloc_free(1);
>> +
>> +		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
>> +		test_mmap_unmap(0);
>> +		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
>> +		test_mmap_unmap(1);
>> +
>> +		for (i = 0; i < nr_bos[subtest]; i++)
>> +			free_userptr_bo(fd, handles[i]);
>> +	}
>> +}
>> +
>> +static void test_single(int fd)
>> +{
>> +	char *ptr, *bo_ptr;
>> +	uint32_t handle = 0;
>> +	unsigned long iter = 0;
>> +	int ret;
>> +	unsigned long map_size = sizeof(linear) + PAGE_SIZE - 1;
>> +
>> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
>> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
>> +	assert(ptr != MAP_FAILED);
>> +
>> +	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
>> +					& ~(PAGE_SIZE - 1));
>
> You might add an ALIGN macro in this file or a suitable header. A couple of
> .c files in lib/ individually define one already.

OK, will add that in the patch series.

Thanks for the review!

Regards,

Tvrtko

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-04-18 17:10     ` Volkin, Bradley D
@ 2014-04-23 13:33       ` Tvrtko Ursulin
  2014-04-23 15:32         ` Volkin, Bradley D
  0 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-04-23 13:33 UTC (permalink / raw)
  To: Volkin, Bradley D; +Cc: Intel-gfx


On 04/18/2014 06:10 PM, Volkin, Bradley D wrote:
> On Wed, Mar 19, 2014 at 04:13:04AM -0700, Tvrtko Ursulin wrote:
>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>
>> A set of userptr test cases to support the new feature.
>>
>> For the eviction and swapping stress testing I have extracted
>> some common behaviour from gem_evict_everything and made both
>> test cases use it to avoid duplicating the code.
>>
>> Both unsynchronized and synchronized userptr objects are
>> tested but the latter set of tests will be skipped if kernel
>> is compiled without MMU_NOTIFIERS.
>>
>> Also, with 32-bit userspace swapping tests are skipped if
>> the system has a lot more RAM than process address space.
>> Forking swapping tests are not skipped since they can still
>> trigger swapping by cumulative effect.
>>
>> v2:
>>     * Fixed dmabuf test.
>>     * Added test for rejecting read-only.
>>     * Fixed ioctl detection for latest kernel patch.
>>
>> v3:
>>     * Updated copy() for Gen8+.
>>     * Fixed ioctl detection on kernels without MMU_NOTIFIERs.
>>
>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>
> A number of the comments I made on patch 3 apply here as well.
> The sizeof(linear) thing is more prevalent in this test, though
> it looks like linear is at least used. Other than those comments
> this looks good to me.

Believe it or not that sizeof(linear) "idiom" I inherited from other 
blitter tests. Personally I don't care one way or another. But since it 
makes sense to get rid of it for the benchmark part, perhaps I should 
change it here as well to be consistent. How strongly do you feel 
strongly about this?

Will see what you reply on the static initializer comment it 3/3, not 
sure what you meant there.

Thanks,

Tvrtko

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-04-23 13:28       ` Tvrtko Ursulin
@ 2014-04-23 15:24         ` Volkin, Bradley D
  0 siblings, 0 replies; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-23 15:24 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

[snip]

On Wed, Apr 23, 2014 at 06:28:54AM -0700, Tvrtko Ursulin wrote:
> On 04/18/2014 12:18 AM, Volkin, Bradley D wrote:
> > On Wed, Mar 19, 2014 at 04:13:06AM -0700, Tvrtko Ursulin wrote:
> >> +static void **handle_ptr_map;
> >> +static unsigned int num_handle_ptr_map;
> >
> > I'd prefer that we explicitly initialize at least num_handle_ptr_map.
> 
> To zero, why?

Partly because I just like explicitly initialized variables and
partly because I forgot that static variables are *guaranteed* to
be initialized to zero vs just-happen-to-be-zero :)

You can leave it as is or change it, I'm fine either way.

Thanks,
Brad

> 
> >> +
> >> +static void add_handle_ptr(uint32_t handle, void *ptr)
> >> +{
> >> +	if (handle >= num_handle_ptr_map) {
> >> +		handle_ptr_map = realloc(handle_ptr_map,
> >> +					 (handle + 1000) * sizeof(void*));
> >> +		num_handle_ptr_map = handle + 1000;
> >> +	}
> >> +
> >> +	handle_ptr_map[handle] = ptr;
> >> +}
> >> +
> >> +static void *get_handle_ptr(uint32_t handle)
> >> +{
> >> +	return handle_ptr_map[handle];
> >> +}
> >> +
> >> +static void free_handle_ptr(uint32_t handle)
> >> +{
> >> +	igt_assert(handle < num_handle_ptr_map);
> >> +	igt_assert(handle_ptr_map[handle]);
> >> +
> >> +	free(handle_ptr_map[handle]);
> >> +	handle_ptr_map[handle] = NULL;
> >> +}
> >> +
> >> +static uint32_t create_userptr_bo(int fd, int size)
> >> +{
> >> +	void *ptr;
> >> +	uint32_t handle;
> >> +	int ret;
> >> +
> >> +	ret = posix_memalign(&ptr, PAGE_SIZE, size);
> >> +	igt_assert(ret == 0);
> >> +
> >> +	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
> >> +	igt_assert(ret == 0);
> >> +	add_handle_ptr(handle, ptr);
> >> +
> >> +	return handle;
> >> +}
> >> +
> >> +static void free_userptr_bo(int fd, uint32_t handle)
> >> +{
> >> +	gem_close(fd, handle);
> >> +	free_handle_ptr(handle);
> >> +}
> >> +
> >> +static int has_userptr(int fd)
> >> +{
> >> +	uint32_t handle = 0;
> >> +	void *ptr;
> >> +	uint32_t oldflags;
> >> +	int ret;
> >> +
> >> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> >> +	oldflags = userptr_flags;
> >> +	gem_userptr_test_unsynchronized();
> >> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> >> +	userptr_flags = oldflags;
> >> +	if (ret != 0) {
> >> +		free(ptr);
> >> +		return 0;
> >> +	}
> >> +
> >> +	gem_close(fd, handle);
> >> +	free(ptr);
> >> +
> >> +	return handle != 0;
> >> +}
> >> +
> >> +static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
> >> +static const unsigned int test_duration_sec = 3;
> >> +
> >> +static volatile unsigned int run_test;
> >> +
> >> +static void alarm_handler(int sig)
> >> +{
> >> +	assert(run_test == 1);
> >> +	run_test = 0;
> >> +}
> >> +
> >> +static void start_test(unsigned int duration)
> >> +{
> >> +	run_test = 1;
> >> +	if (duration == 0)
> >> +		duration = test_duration_sec;
> >> +	signal(SIGALRM, alarm_handler);
> >> +	alarm(duration);
> >> +}
> >> +
> >> +static void exchange_ptr(void *array, unsigned i, unsigned j)
> >> +{
> >> +	void **arr, *tmp;
> >> +	arr = (void **)array;
> >> +
> >> +	tmp = arr[i];
> >> +	arr[i] = arr[j];
> >> +	arr[j] = tmp;
> >> +}
> >> +
> >> +static void test_malloc_free(int random)
> >> +{
> >> +	unsigned long iter = 0;
> >> +	unsigned int i, tot = 1000;
> >> +	void *ptr[tot];
> >> +
> >> +	start_test(test_duration_sec);
> >> +
> >> +	while (run_test) {
> >> +		for (i = 0; i < tot; i++) {
> >> +			ptr[i] = malloc(1000);
> >> +			assert(ptr[i]);
> >> +		}
> >> +		if (random)
> >> +			igt_permute_array(ptr, tot, exchange_ptr);
> >> +		for (i = 0; i < tot; i++)
> >> +			free(ptr[i]);
> >> +		iter++;
> >> +	}
> >> +
> >> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> >> +}
> >> +
> >> +static void test_malloc_realloc_free(int random)
> >> +{
> >> +	unsigned long iter = 0;
> >> +	unsigned int i, tot = 1000;
> >> +	void *ptr[tot];
> >> +
> >> +	start_test(test_duration_sec);
> >> +
> >> +	while (run_test) {
> >> +		for (i = 0; i < tot; i++) {
> >> +			ptr[i] = malloc(1000);
> >> +			assert(ptr[i]);
> >> +		}
> >> +		if (random)
> >> +			igt_permute_array(ptr, tot, exchange_ptr);
> >> +		for (i = 0; i < tot; i++) {
> >> +			ptr[i] = realloc(ptr[i], 2000);
> >> +			assert(ptr[i]);
> >> +		}
> >> +		if (random)
> >> +			igt_permute_array(ptr, tot, exchange_ptr);
> >> +		for (i = 0; i < tot; i++)
> >> +			free(ptr[i]);
> >> +		iter++;
> >> +	}
> >> +
> >> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> >> +}
> >> +
> >> +static void test_mmap_unmap(int random)
> >> +{
> >> +	unsigned long iter = 0;
> >> +	unsigned int i, tot = 1000;
> >> +	void *ptr[tot];
> >> +
> >> +	start_test(test_duration_sec);
> >> +
> >> +	while (run_test) {
> >> +		for (i = 0; i < tot; i++) {
> >> +			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
> >> +					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> >> +			assert(ptr[i] != MAP_FAILED);
> >> +		}
> >> +		if (random)
> >> +			igt_permute_array(ptr, tot, exchange_ptr);
> >> +		for (i = 0; i < tot; i++)
> >> +			munmap(ptr[i], 1000);
> >> +		iter++;
> >> +	}
> >> +
> >> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> >> +}
> >> +
> >> +static void test_ptr_read(void *ptr)
> >> +{
> >> +	unsigned long iter = 0;
> >> +	volatile unsigned long *p;
> >> +	unsigned long i, loops;
> >> +	register unsigned long v;
> >> +
> >> +	loops = sizeof(linear) / sizeof(unsigned long) / 4;
> >> +
> >> +	start_test(test_duration_sec);
> >> +
> >> +	while (run_test) {
> >> +		p = (unsigned long *)ptr;
> >> +		for (i = 0; i < loops; i++) {
> >> +			v = *p++;
> >> +			v = *p++;
> >> +			v = *p++;
> >> +			v = *p++;
> >> +		}
> >> +		iter++;
> >> +	}
> >> +
> >> +	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
> >> +}
> >> +
> >> +static void test_ptr_write(void *ptr)
> >> +{
> >> +	unsigned long iter = 0;
> >> +	volatile unsigned long *p;
> >> +	register unsigned long i, loops;
> >> +
> >> +	loops = sizeof(linear) / sizeof(unsigned long) / 4;
> >> +
> >> +	start_test(test_duration_sec);
> >> +
> >> +	while (run_test) {
> >> +		p = (unsigned long *)ptr;
> >> +		for (i = 0; i < loops; i++) {
> >> +			*p++ = i;
> >> +			*p++ = i;
> >> +			*p++ = i;
> >> +			*p++ = i;
> >> +		}
> >> +		iter++;
> >> +	}
> >> +
> >> +	printf("%8lu MB/s\n", iter / test_duration_sec * sizeof(linear) / 1000000);
> >> +}
> >> +
> >> +static void test_impact(int fd)
> >> +{
> >> +	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
> >> +	unsigned int subtest, i;
> >> +	uint32_t handles[nr_bos[total-1]];
> >> +	void *ptr;
> >> +	char buffer[sizeof(linear)];
> >> +
> >> +	for (subtest = 0; subtest < total; subtest++) {
> >> +		for (i = 0; i < nr_bos[subtest]; i++)
> >> +			handles[i] = create_userptr_bo(fd, sizeof(linear));
> >> +
> >> +		if (nr_bos[subtest] > 0)
> >> +			ptr = get_handle_ptr(handles[0]);
> >> +		else
> >> +			ptr = buffer;
> >> +
> >> +		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
> >> +		test_ptr_read(ptr);
> >> +
> >> +		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
> >> +		test_ptr_write(ptr);
> >> +
> >> +		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
> >> +		test_malloc_free(0);
> >> +		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
> >> +		test_malloc_free(1);
> >> +
> >> +		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
> >> +		test_malloc_realloc_free(0);
> >> +		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
> >> +		test_malloc_realloc_free(1);
> >> +
> >> +		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
> >> +		test_mmap_unmap(0);
> >> +		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
> >> +		test_mmap_unmap(1);
> >> +
> >> +		for (i = 0; i < nr_bos[subtest]; i++)
> >> +			free_userptr_bo(fd, handles[i]);
> >> +	}
> >> +}
> >> +
> >> +static void test_single(int fd)
> >> +{
> >> +	char *ptr, *bo_ptr;
> >> +	uint32_t handle = 0;
> >> +	unsigned long iter = 0;
> >> +	int ret;
> >> +	unsigned long map_size = sizeof(linear) + PAGE_SIZE - 1;
> >> +
> >> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> >> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> >> +	assert(ptr != MAP_FAILED);
> >> +
> >> +	bo_ptr = (char *)(((unsigned long)ptr + (PAGE_SIZE - 1))
> >> +					& ~(PAGE_SIZE - 1));
> >
> > You might add an ALIGN macro in this file or a suitable header. A couple of
> > .c files in lib/ individually define one already.
> 
> OK, will add that in the patch series.
> 
> Thanks for the review!
> 
> Regards,
> 
> Tvrtko
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-04-23 13:33       ` Tvrtko Ursulin
@ 2014-04-23 15:32         ` Volkin, Bradley D
  2014-04-23 17:53           ` Daniel Vetter
  0 siblings, 1 reply; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-23 15:32 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

On Wed, Apr 23, 2014 at 06:33:40AM -0700, Tvrtko Ursulin wrote:
> 
> On 04/18/2014 06:10 PM, Volkin, Bradley D wrote:
> > On Wed, Mar 19, 2014 at 04:13:04AM -0700, Tvrtko Ursulin wrote:
> >> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> >>
> >> A set of userptr test cases to support the new feature.
> >>
> >> For the eviction and swapping stress testing I have extracted
> >> some common behaviour from gem_evict_everything and made both
> >> test cases use it to avoid duplicating the code.
> >>
> >> Both unsynchronized and synchronized userptr objects are
> >> tested but the latter set of tests will be skipped if kernel
> >> is compiled without MMU_NOTIFIERS.
> >>
> >> Also, with 32-bit userspace swapping tests are skipped if
> >> the system has a lot more RAM than process address space.
> >> Forking swapping tests are not skipped since they can still
> >> trigger swapping by cumulative effect.
> >>
> >> v2:
> >>     * Fixed dmabuf test.
> >>     * Added test for rejecting read-only.
> >>     * Fixed ioctl detection for latest kernel patch.
> >>
> >> v3:
> >>     * Updated copy() for Gen8+.
> >>     * Fixed ioctl detection on kernels without MMU_NOTIFIERs.
> >>
> >> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> >
> > A number of the comments I made on patch 3 apply here as well.
> > The sizeof(linear) thing is more prevalent in this test, though
> > it looks like linear is at least used. Other than those comments
> > this looks good to me.
> 
> Believe it or not that sizeof(linear) "idiom" I inherited from other 
> blitter tests. Personally I don't care one way or another. But since it 
> makes sense to get rid of it for the benchmark part, perhaps I should 
> change it here as well to be consistent. How strongly do you feel 
> strongly about this?

I think changing it would be slightly more readable, but if it's
consistent with other blit tests then I don't feel too strongly
about it. In fact, consistency with the other tests might be the
better approach. I'm fine with whichever approach you prefer.

Thanks,
Brad

> 
> Will see what you reply on the static initializer comment it 3/3, not 
> sure what you meant there.
> 
> Thanks,
> 
> Tvrtko

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-02-26 16:17 [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
                   ` (3 preceding siblings ...)
  2014-03-19 11:13 ` [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
@ 2014-04-23 16:38 ` Tvrtko Ursulin
  2014-04-23 16:38   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
                     ` (2 more replies)
  2014-04-24  9:07 ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
  5 siblings, 3 replies; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-04-23 16:38 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

A set of userptr test cases to support the new feature.

For the eviction and swapping stress testing I have extracted
some common behaviour from gem_evict_everything and made both
test cases use it to avoid duplicating the code.

Both unsynchronized and synchronized userptr objects are
tested but the latter set of tests will be skipped if kernel
is compiled without MMU_NOTIFIERS.

Also, with 32-bit userspace swapping tests are skipped if
the system has a lot more RAM than process address space.
Forking swapping tests are not skipped since they can still
trigger swapping by cumulative effect.

v2:
   * Fixed dmabuf test.
   * Added test for rejecting read-only.
   * Fixed ioctl detection for latest kernel patch.

v3:
   * Use ALIGN macro.
   * Catchup with big lib/ reorganization.
   * Fixed up some warnings.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 tests/.gitignore          |    1 +
 tests/Makefile.sources    |    1 +
 tests/gem_userptr_blits.c | 1247 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1249 insertions(+)
 create mode 100644 tests/gem_userptr_blits.c

diff --git a/tests/.gitignore b/tests/.gitignore
index 146bab0..ff193bd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -95,6 +95,7 @@ gem_tiling_max_stride
 gem_unfence_active_buffers
 gem_unref_active_buffers
 gem_vmap_blits
+gem_userptr_blits
 gem_wait_render_timeout
 gem_write_read_ring_switch
 gen3_mixed_blits
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index c957ace..09d6aa3 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -121,6 +121,7 @@ TESTS_progs = \
 	gem_unfence_active_buffers \
 	gem_unref_active_buffers \
 	gem_vmap_blits \
+	gem_userptr_blits \
 	gem_wait_render_timeout \
 	gen3_mixed_blits \
 	gen3_render_linear_blits \
diff --git a/tests/gem_userptr_blits.c b/tests/gem_userptr_blits.c
new file mode 100644
index 0000000..03af58e
--- /dev/null
+++ b/tests/gem_userptr_blits.c
@@ -0,0 +1,1247 @@
+/*
+ * Copyright © 2009-2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *    Chris Wilson <chris@chris-wilson.co.uk>
+ *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+ *
+ */
+
+/** @file gem_userptr_blits.c
+ *
+ * This is a test of doing many blits using a mixture of normal system pages
+ * and uncached linear buffers, with a working set larger than the
+ * aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_chipset.h"
+#include "ioctl_wrappers.h"
+
+#include "eviction_common.c"
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+#define LOCAL_I915_GEM_USERPTR       0x34
+#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
+struct local_i915_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint32_t flags;
+#define LOCAL_I915_USERPTR_READ_ONLY (1<<0)
+#define LOCAL_I915_USERPTR_UNSYNCHRONIZED (1<<31)
+	uint32_t handle;
+};
+
+static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+
+#define WIDTH 512
+#define HEIGHT 512
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static void gem_userptr_test_unsynchronized(void)
+{
+	userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+}
+
+static void gem_userptr_test_synchronized(void)
+{
+	userptr_flags = 0;
+}
+
+static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	userptr.user_ptr = (uintptr_t)ptr;
+	userptr.user_size = size;
+	userptr.flags = userptr_flags;
+	if (read_only)
+		userptr.flags |= LOCAL_I915_USERPTR_READ_ONLY;
+
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	if (ret)
+		ret = errno;
+	igt_skip_on_f(ret == ENODEV &&
+		      (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) == 0 &&
+		      !read_only,
+		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
+	if (ret == 0)
+		*handle = userptr.handle;
+
+	return ret;
+}
+
+
+static void gem_userptr_sync(int fd, uint32_t handle)
+{
+	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+}
+
+static void
+copy(int fd, uint32_t dst, uint32_t src, unsigned int error)
+{
+	uint32_t batch[12];
+	struct drm_i915_gem_relocation_entry reloc[2];
+	struct drm_i915_gem_exec_object2 obj[3];
+	struct drm_i915_gem_execbuffer2 exec;
+	uint32_t handle;
+	int ret, i=0;
+
+	batch[i++] = XY_SRC_COPY_BLT_CMD |
+		  XY_SRC_COPY_BLT_WRITE_ALPHA |
+		  XY_SRC_COPY_BLT_WRITE_RGB;
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i - 1] |= 8;
+	else
+		batch[i - 1] |= 6;
+
+	batch[i++] = (3 << 24) | /* 32 bits */
+		  (0xcc << 16) | /* copy ROP */
+		  WIDTH*4;
+	batch[i++] = 0; /* dst x1,y1 */
+	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+	batch[i++] = 0; /* dst reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = 0; /* src x1,y1 */
+	batch[i++] = WIDTH*4;
+	batch[i++] = 0; /* src reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = MI_BATCH_BUFFER_END;
+	batch[i++] = MI_NOOP;
+
+	handle = gem_create(fd, 4096);
+	gem_write(fd, handle, 0, batch, sizeof(batch));
+
+	reloc[0].target_handle = dst;
+	reloc[0].delta = 0;
+	reloc[0].offset = 4 * sizeof(batch[0]);
+	reloc[0].presumed_offset = 0;
+	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
+	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+	reloc[1].target_handle = src;
+	reloc[1].delta = 0;
+	reloc[1].offset = 7 * sizeof(batch[0]);
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		reloc[1].offset += sizeof(batch[0]);
+	reloc[1].presumed_offset = 0;
+	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
+	reloc[1].write_domain = 0;
+
+	obj[0].handle = dst;
+	obj[0].relocation_count = 0;
+	obj[0].relocs_ptr = 0;
+	obj[0].alignment = 0;
+	obj[0].offset = 0;
+	obj[0].flags = 0;
+	obj[0].rsvd1 = 0;
+	obj[0].rsvd2 = 0;
+
+	obj[1].handle = src;
+	obj[1].relocation_count = 0;
+	obj[1].relocs_ptr = 0;
+	obj[1].alignment = 0;
+	obj[1].offset = 0;
+	obj[1].flags = 0;
+	obj[1].rsvd1 = 0;
+	obj[1].rsvd2 = 0;
+
+	obj[2].handle = handle;
+	obj[2].relocation_count = 2;
+	obj[2].relocs_ptr = (uintptr_t)reloc;
+	obj[2].alignment = 0;
+	obj[2].offset = 0;
+	obj[2].flags = 0;
+	obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+	exec.buffers_ptr = (uintptr_t)obj;
+	exec.buffer_count = 3;
+	exec.batch_start_offset = 0;
+	exec.batch_len = i * 4;
+	exec.DR1 = exec.DR4 = 0;
+	exec.num_cliprects = 0;
+	exec.cliprects_ptr = 0;
+	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+	i915_execbuffer2_set_context_id(exec, 0);
+	exec.rsvd2 = 0;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+	if (ret)
+		ret = errno;
+
+	if (error == ~0)
+		igt_assert(ret != 0);
+	else
+		igt_assert(ret == error);
+
+	gem_close(fd, handle);
+}
+
+static void
+blit(int fd, uint32_t dst, uint32_t src, uint32_t *all_bo, int n_bo, int error)
+{
+	uint32_t batch[12];
+	struct drm_i915_gem_relocation_entry reloc[2];
+	struct drm_i915_gem_exec_object2 *obj;
+	struct drm_i915_gem_execbuffer2 exec;
+	uint32_t handle;
+	int n, ret, i=0;
+
+	batch[i++] = XY_SRC_COPY_BLT_CMD |
+		  XY_SRC_COPY_BLT_WRITE_ALPHA |
+		  XY_SRC_COPY_BLT_WRITE_RGB;
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i - 1] |= 8;
+	else
+		batch[i - 1] |= 6;
+	batch[i++] = (3 << 24) | /* 32 bits */
+		  (0xcc << 16) | /* copy ROP */
+		  WIDTH*4;
+	batch[i++] = 0; /* dst x1,y1 */
+	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+	batch[i++] = 0; /* dst reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = 0; /* src x1,y1 */
+	batch[i++] = WIDTH*4;
+	batch[i++] = 0; /* src reloc */
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		batch[i++] = 0;
+	batch[i++] = MI_BATCH_BUFFER_END;
+	batch[i++] = MI_NOOP;
+
+	handle = gem_create(fd, 4096);
+	gem_write(fd, handle, 0, batch, sizeof(batch));
+
+	reloc[0].target_handle = dst;
+	reloc[0].delta = 0;
+	reloc[0].offset = 4 * sizeof(batch[0]);
+	reloc[0].presumed_offset = 0;
+	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+	reloc[1].target_handle = src;
+	reloc[1].delta = 0;
+	reloc[1].offset = 7 * sizeof(batch[0]);
+	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+		reloc[1].offset += sizeof(batch[0]);
+	reloc[1].presumed_offset = 0;
+	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
+	reloc[1].write_domain = 0;
+
+	obj = calloc(n_bo + 1, sizeof(*obj));
+	for (n = 0; n < n_bo; n++)
+		obj[n].handle = all_bo[n];
+	obj[n].handle = handle;
+	obj[n].relocation_count = 2;
+	obj[n].relocs_ptr = (uintptr_t)reloc;
+
+	exec.buffers_ptr = (uintptr_t)obj;
+	exec.buffer_count = n_bo + 1;
+	exec.batch_start_offset = 0;
+	exec.batch_len = i * 4;
+	exec.DR1 = exec.DR4 = 0;
+	exec.num_cliprects = 0;
+	exec.cliprects_ptr = 0;
+	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+	i915_execbuffer2_set_context_id(exec, 0);
+	exec.rsvd2 = 0;
+
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+	if (ret)
+		ret = errno;
+
+	igt_assert(ret == error);
+
+	gem_close(fd, handle);
+	free(obj);
+}
+
+static uint32_t
+create_userptr(int fd, uint32_t val, uint32_t *ptr)
+{
+	uint32_t handle;
+	int i, ret;
+
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
+	igt_assert(ret == 0);
+	igt_assert(handle != 0);
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		ptr[i] = val++;
+
+	return handle;
+}
+
+static void **handle_ptr_map;
+static unsigned int num_handle_ptr_map;
+
+static void add_handle_ptr(uint32_t handle, void *ptr)
+{
+	if (handle >= num_handle_ptr_map) {
+		handle_ptr_map = realloc(handle_ptr_map,
+					 (handle + 1000) * sizeof(void*));
+		num_handle_ptr_map = handle + 1000;
+	}
+
+	handle_ptr_map[handle] = ptr;
+}
+
+static void *get_handle_ptr(uint32_t handle)
+{
+	return handle_ptr_map[handle];
+}
+
+static void free_handle_ptr(uint32_t handle)
+{
+	igt_assert(handle < num_handle_ptr_map);
+	igt_assert(handle_ptr_map[handle]);
+
+	free(handle_ptr_map[handle]);
+	handle_ptr_map[handle] = NULL;
+}
+
+static uint32_t create_userptr_bo(int fd, int size)
+{
+	void *ptr;
+	uint32_t handle;
+	int ret;
+
+	ret = posix_memalign(&ptr, PAGE_SIZE, size);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
+	igt_assert(ret == 0);
+	add_handle_ptr(handle, ptr);
+
+	return handle;
+}
+
+static void clear(int fd, uint32_t handle, int size)
+{
+	void *ptr = get_handle_ptr(handle);
+
+	igt_assert(ptr != NULL);
+
+	memset(ptr, 0, size);
+}
+
+static void free_userptr_bo(int fd, uint32_t handle)
+{
+	gem_close(fd, handle);
+	free_handle_ptr(handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+	uint32_t handle;
+	int i;
+
+	handle = gem_create(fd, sizeof(linear));
+
+	/* Fill the BO with dwords starting at val */
+	for (i = 0; i < WIDTH*HEIGHT; i++)
+		linear[i] = val++;
+	gem_write(fd, handle, 0, linear, sizeof(linear));
+
+	return handle;
+}
+
+static void
+check_cpu(uint32_t *ptr, uint32_t val)
+{
+	int i;
+
+	for (i = 0; i < WIDTH*HEIGHT; i++) {
+		if (ptr[i] != val) {
+			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+				"at offset 0x%08x\n",
+				val, ptr[i], i * 4);
+			abort();
+		}
+		val++;
+	}
+}
+
+static void
+check_gpu(int fd, uint32_t handle, uint32_t val)
+{
+	gem_read(fd, handle, 0, linear, sizeof(linear));
+	check_cpu(linear, val);
+}
+
+static int has_userptr(int fd)
+{
+	uint32_t handle = 0;
+	void *ptr;
+	uint32_t oldflags;
+	int ret;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+	oldflags = userptr_flags;
+	gem_userptr_test_unsynchronized();
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	userptr_flags = oldflags;
+	if (ret != 0) {
+		free(ptr);
+		return 0;
+	}
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return handle != 0;
+}
+
+static int test_input_checking(int fd)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	/* Invalid flags. */
+	userptr.user_ptr = 0;
+	userptr.user_size = 0;
+	userptr.flags = ~0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	/* Too big. */
+	userptr.user_ptr = 0;
+	userptr.user_size = ~0;
+	userptr.flags = 0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	/* Both wrong. */
+	userptr.user_ptr = 0;
+	userptr.user_size = ~0;
+	userptr.flags = ~0;
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	igt_assert(ret != 0);
+
+	return 0;
+}
+
+static int test_access_control(int fd)
+{
+	igt_fork(child, 1) {
+		void *ptr;
+		int ret;
+		uint32_t handle;
+
+		igt_drop_root();
+
+		/* CAP_SYS_ADMIN is needed for UNSYNCHRONIZED mappings. */
+		gem_userptr_test_unsynchronized();
+
+		igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+		ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+		if (ret == 0)
+			gem_close(fd, handle);
+		free(ptr);
+		igt_assert(ret == EPERM);
+	}
+
+	igt_waitchildren();
+
+	return 0;
+}
+
+static int test_invalid_mapping(int fd)
+{
+	int ret;
+	uint32_t handle, handle2;
+	void *ptr;
+
+	/* NULL pointer. */
+	ret = gem_userptr(fd, NULL, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
+	gem_close(fd, handle);
+
+	/* GTT mapping */
+	handle = create_bo(fd, 0);
+	ptr = gem_mmap__gtt(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
+	if (ptr == NULL)
+		gem_close(fd, handle);
+	assert(ptr != NULL);
+	assert(((unsigned long)ptr & (PAGE_SIZE - 1)) == 0);
+	assert((sizeof(linear) & (PAGE_SIZE - 1)) == 0);
+	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle2);
+	igt_assert(ret == 0);
+	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
+	gem_close(fd, handle2);
+	munmap(ptr, sizeof(linear));
+	gem_close(fd, handle);
+
+	return 0;
+}
+
+static int test_forbidden_ops(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+	char buf[PAGE_SIZE];
+	struct drm_i915_gem_pread gem_pread;
+	struct drm_i915_gem_pwrite gem_pwrite;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	gem_pread.handle = handle;
+	gem_pread.offset = 0;
+	gem_pread.size = PAGE_SIZE;
+	gem_pread.data_ptr = (uintptr_t)buf;
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
+	if (ret == 0) {
+		gem_close(fd, handle);
+		free(ptr);
+	}
+	igt_assert(ret != 0);
+
+	gem_pwrite.handle = handle;
+	gem_pwrite.offset = 0;
+	gem_pwrite.size = PAGE_SIZE;
+	gem_pwrite.data_ptr = (uintptr_t)buf;
+	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
+	if (ret == 0) {
+		gem_close(fd, handle);
+		free(ptr);
+	}
+	igt_assert(ret != 0);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static char counter;
+
+static void (*orig_sigbus)(int sig, siginfo_t *info, void *param);
+static unsigned long sigbus_start;
+static long sigbus_cnt = -1;
+
+static void
+check_bo(int fd1, uint32_t handle1, int is_userptr, int fd2, uint32_t handle2)
+{
+	char *ptr1, *ptr2;
+	int i;
+	unsigned long size = sizeof(linear);
+
+	if (is_userptr)
+		ptr1 = get_handle_ptr(handle1);
+	else
+		ptr1 = gem_mmap(fd1, handle1, sizeof(linear), PROT_READ | PROT_WRITE);
+
+	ptr2 = gem_mmap(fd2, handle2, sizeof(linear), PROT_READ | PROT_WRITE);
+
+	igt_assert(ptr1);
+	igt_assert(ptr2);
+
+	sigbus_start = (unsigned long)ptr2;
+
+	if (sigbus_cnt == 0)
+		size = 1;
+
+	/* check whether it's still our old object first. */
+	for (i = 0; i < size; i++) {
+		igt_assert(ptr1[i] == counter);
+		igt_assert(ptr2[i] == counter);
+	}
+
+	counter++;
+
+	if (size > 1) {
+		memset(ptr1, counter, size);
+		igt_assert(memcmp(ptr1, ptr2, size) == 0);
+	}
+
+	if (!is_userptr)
+		munmap(ptr1, sizeof(linear));
+	munmap(ptr2, sizeof(linear));
+}
+
+static int export_handle(int fd, uint32_t handle, int *outfd)
+{
+	struct drm_prime_handle args;
+	int ret;
+
+	args.handle = handle;
+	args.flags = DRM_CLOEXEC;
+	args.fd = -1;
+
+	ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
+	if (ret)
+		ret = errno;
+	*outfd = args.fd;
+
+	return ret;
+}
+
+static void sigbus(int sig, siginfo_t *info, void *param)
+{
+	unsigned long ptr = (unsigned long)info->si_addr;
+	void *addr;
+
+	if (ptr >= sigbus_start &&
+	    ptr <= (sigbus_start + sizeof(linear))) {
+		sigbus_cnt++;
+		addr = mmap((void *)ptr, sizeof(linear), PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
+		if ((unsigned long)addr == ptr) {
+			memset(addr, counter, sizeof(linear));
+			return;
+		}
+	}
+
+	if (orig_sigbus)
+		orig_sigbus(sig, info, param);
+	assert(0);
+}
+
+static int test_dmabuf(void)
+{
+	int fd1, fd2;
+	uint32_t handle, handle_import1, handle_import2, handle_selfimport;
+	int dma_buf_fd = -1;
+	int ret;
+	struct sigaction sigact, orig_sigact;
+
+	fd1 = drm_open_any();
+	fd2 = drm_open_any();
+
+	handle = create_userptr_bo(fd1, sizeof(linear));
+
+	ret = export_handle(fd1, handle, &dma_buf_fd);
+	if (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) {
+		igt_assert(ret == EINVAL);
+		free_userptr_bo(fd1, handle);
+
+		return 0;
+	} else {
+		igt_assert(ret == 0);
+		igt_assert(dma_buf_fd >= 0);
+	}
+	handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd);
+	check_bo(fd1, handle, 1, fd2, handle_import1);
+
+	/* reimport should give us the same handle so that userspace can check
+	 * whether it has that bo already somewhere. */
+	handle_import2 = prime_fd_to_handle(fd2, dma_buf_fd);
+	igt_assert(handle_import1 == handle_import2);
+
+	/* Same for re-importing on the exporting fd. */
+	handle_selfimport = prime_fd_to_handle(fd1, dma_buf_fd);
+	igt_assert(handle == handle_selfimport);
+
+	/* close dma_buf, check whether nothing disappears. */
+	close(dma_buf_fd);
+	check_bo(fd1, handle, 1, fd2, handle_import1);
+
+	/* destroy userptr object and expect SIGBUS */
+	free_userptr_bo(fd1, handle);
+	sigact.sa_sigaction = sigbus;
+	sigact.sa_flags = SA_SIGINFO;
+	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
+	assert(ret == 0);
+	orig_sigbus = orig_sigact.sa_sigaction;
+	sigbus_cnt = 0;
+	check_bo(fd2, handle_import1, 0, fd2, handle_import1);
+	assert(sigbus_cnt > 0);
+	sigact.sa_sigaction = orig_sigbus;
+	sigact.sa_flags = SA_SIGINFO;
+	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
+	assert(ret == 0);
+
+	gem_close(fd2, handle_import1);
+	close(fd1);
+	close(fd2);
+
+	return 0;
+}
+
+static int test_usage_restrictions(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE * 2) == 0);
+
+	/* Address not aligned. */
+	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Size not rounded to page size. */
+	ret = gem_userptr(fd, ptr, PAGE_SIZE - 1, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Both wrong. */
+	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE - 1, 0, &handle);
+	igt_assert(ret != 0);
+
+	/* Read-only not supported. */
+	ret = gem_userptr(fd, (char *)ptr, PAGE_SIZE, 1, &handle);
+	igt_assert(ret != 0);
+
+	free(ptr);
+
+	return 0;
+}
+
+static int test_create_destroy(int fd)
+{
+	void *ptr;
+	int ret;
+	uint32_t handle;
+
+	igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static int test_coherency(int fd, int count)
+{
+	uint32_t *memory;
+	uint32_t *cpu, *cpu_val;
+	uint32_t *gpu, *gpu_val;
+	uint32_t start = 0;
+	int i, ret;
+
+	printf("Using 2x%d 1MiB buffers\n", count);
+
+	ret = posix_memalign((void **)&memory, PAGE_SIZE, count*sizeof(linear));
+	if (ret != 0 || memory == NULL) {
+		fprintf(stderr, "Unable to allocate %lld bytes\n",
+			(long long)count*sizeof(linear));
+		return 1;
+	}
+
+	gpu = malloc(sizeof(uint32_t)*count*4);
+	gpu_val = gpu + count;
+	cpu = gpu_val + count;
+	cpu_val = cpu + count;
+
+	for (i = 0; i < count; i++) {
+		gpu[i] = create_bo(fd, start);
+		gpu_val[i] = start;
+		start += WIDTH*HEIGHT;
+	}
+
+	for (i = 0; i < count; i++) {
+		cpu[i] = create_userptr(fd, start, memory+i*WIDTH*HEIGHT);
+		cpu_val[i] = start;
+		start += WIDTH*HEIGHT;
+	}
+
+	printf("Verifying initialisation...\n");
+	for (i = 0; i < count; i++) {
+		check_gpu(fd, gpu[i], gpu_val[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+	}
+
+	printf("Cyclic blits cpu->gpu, forward...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = i % count;
+		int dst = (i + 1) % count;
+
+		copy(fd, gpu[dst], cpu[src], 0);
+		gpu_val[dst] = cpu_val[src];
+	}
+	for (i = 0; i < count; i++)
+		check_gpu(fd, gpu[i], gpu_val[i]);
+
+	printf("Cyclic blits gpu->cpu, backward...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = (i + 1) % count;
+		int dst = i % count;
+
+		copy(fd, cpu[dst], gpu[src], 0);
+		cpu_val[dst] = gpu_val[src];
+	}
+	for (i = 0; i < count; i++) {
+		gem_userptr_sync(fd, cpu[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+	}
+
+	printf("Random blits...\n");
+	for (i = 0; i < count * 4; i++) {
+		int src = random() % count;
+		int dst = random() % count;
+
+		if (random() & 1) {
+			copy(fd, gpu[dst], cpu[src], 0);
+			gpu_val[dst] = cpu_val[src];
+		} else {
+			copy(fd, cpu[dst], gpu[src], 0);
+			cpu_val[dst] = gpu_val[src];
+		}
+	}
+	for (i = 0; i < count; i++) {
+		check_gpu(fd, gpu[i], gpu_val[i]);
+		gem_close(fd, gpu[i]);
+
+		gem_userptr_sync(fd, cpu[i]);
+		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+		gem_close(fd, cpu[i]);
+	}
+
+	free(gpu);
+	free(memory);
+
+	return 0;
+}
+
+static struct igt_eviction_test_ops fault_ops = {
+	.create = create_userptr_bo,
+	.close = free_userptr_bo,
+	.copy = blit,
+	.clear = clear,
+};
+
+static int can_swap(void)
+{
+	unsigned long as, ram;
+
+	/* Cannot swap if not enough address space */
+
+	/* FIXME: Improve check criteria. */
+	if (sizeof(void*) < 8)
+		as = 3 * 1024;
+	else
+		as = 256 * 1024; /* Just a big number */
+
+	ram = intel_get_total_ram_mb();
+
+	if ((as - 128) < (ram - 256))
+		return 0;
+
+	return 1;
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static void test_forking_evictions(int fd, int size, int count,
+			     unsigned flags)
+{
+	int trash_count;
+	int num_threads;
+
+	trash_count = intel_get_total_ram_mb() * 11 / 10;
+	/* Use the fact test will spawn a number of child
+	 * processes meaning swapping will be triggered system
+	 * wide even if one process on it's own can't do it.
+	 */
+	num_threads = min(sysconf(_SC_NPROCESSORS_ONLN) * 4, 12);
+	trash_count /= num_threads;
+	if (count > trash_count)
+		count = trash_count;
+
+	forking_evictions(fd, &fault_ops, size, count, trash_count, flags);
+}
+
+static void test_swapping_evictions(int fd, int size, int count)
+{
+	int trash_count;
+
+	igt_skip_on_f(!can_swap(),
+		"Not enough process address space for swapping tests.\n");
+
+	trash_count = intel_get_total_ram_mb() * 11 / 10;
+
+	swapping_evictions(fd, &fault_ops, size, count, trash_count);
+}
+
+static void test_minor_evictions(int fd, int size, int count)
+{
+	minor_evictions(fd, &fault_ops, size, count);
+}
+
+static void test_major_evictions(int fd, int size, int count)
+{
+	major_evictions(fd, &fault_ops, size, count);
+}
+
+static int test_overlap(int fd, int expected)
+{
+	char *ptr;
+	int ret;
+	uint32_t handle, handle2;
+
+	igt_assert(posix_memalign((void *)&ptr, PAGE_SIZE, PAGE_SIZE * 3) == 0);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE, 0, &handle);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle2);
+	igt_assert(ret == 0);
+	gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE * 2, PAGE_SIZE, 0, &handle2);
+	igt_assert(ret == 0);
+	gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE * 2, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE * 2, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	ret = gem_userptr(fd, ptr, PAGE_SIZE * 3, 0, &handle2);
+	igt_assert(ret == expected);
+	if (ret == 0)
+		gem_close(fd, handle2);
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return 0;
+}
+
+static int test_unmap(int fd, int expected)
+{
+	char *ptr, *bo_ptr;
+	const unsigned int num_obj = 3;
+	unsigned int i;
+	uint32_t bo[num_obj + 1];
+	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
+	int ret;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
+
+	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
+		igt_assert(ret == 0);
+	}
+
+	bo[num_obj] = create_bo(fd, 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], 0);
+
+	ret = munmap(ptr, map_size);
+	assert(ret == 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], expected);
+
+	for (i = 0; i < (num_obj + 1); i++)
+		gem_close(fd, bo[i]);
+
+	return 0;
+}
+
+static int test_unmap_after_close(int fd)
+{
+	char *ptr, *bo_ptr;
+	const unsigned int num_obj = 3;
+	unsigned int i;
+	uint32_t bo[num_obj + 1];
+	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
+	int ret;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
+
+	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
+		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
+		igt_assert(ret == 0);
+	}
+
+	bo[num_obj] = create_bo(fd, 0);
+
+	for (i = 0; i < num_obj; i++)
+		copy(fd, bo[num_obj], bo[i], 0);
+
+	for (i = 0; i < (num_obj + 1); i++)
+		gem_close(fd, bo[i]);
+
+	ret = munmap(ptr, map_size);
+	assert(ret == 0);
+
+	return 0;
+}
+
+static int test_unmap_cycles(int fd, int expected)
+{
+	int i;
+
+	for (i = 0; i < 1000; i++)
+		test_unmap(fd, expected);
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	uint64_t aperture_size;
+	unsigned int total_ram;
+	int fd = -1, count = 0, size = 0, ret;
+
+	igt_skip_on_simulation();
+
+	igt_subtest_init(argc, argv);
+
+	igt_fixture {
+		fd = drm_open_any();
+		igt_assert(fd >= 0);
+
+		ret = has_userptr(fd);
+		igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
+			      strerror(errno), ret);
+
+		size = sizeof(linear);
+
+		aperture_size = gem_aperture_size(fd);
+		printf("Aperture size is %lu MiB\n", (long)(aperture_size / (1024*1024)));
+
+		if (argc > 1)
+			count = atoi(argv[1]);
+		if (count == 0)
+			count = 2 * aperture_size / (1024*1024) / 3;
+
+		total_ram = intel_get_total_ram_mb();
+		printf("Total RAM is %u MiB\n", total_ram);
+
+		if (count > total_ram * 3 / 4) {
+			count = intel_get_total_ram_mb() * 3 / 4;
+			printf("Not enough RAM to run test, reducing buffer count.\n");
+		}
+	}
+
+	igt_subtest("input-checking")
+		test_input_checking(fd);
+
+	igt_subtest("usage-restrictions")
+		test_usage_restrictions(fd);
+
+	igt_subtest("invalid-mapping")
+		test_invalid_mapping(fd);
+
+	igt_subtest("forbidden-operations")
+		test_forbidden_ops(fd);
+
+	printf("Testing unsynchronized mappings...\n");
+	gem_userptr_test_unsynchronized();
+
+	igt_subtest("create-destroy-unsync")
+		test_create_destroy(fd);
+
+	igt_subtest("unsync-overlap")
+		test_overlap(fd, 0);
+
+	igt_subtest("unsync-unmap")
+		test_unmap(fd, 0);
+
+	igt_subtest("unsync-unmap-cycles")
+		test_unmap_cycles(fd, 0);
+
+	igt_subtest("unsync-unmap-after-close")
+		test_unmap_after_close(fd);
+
+	igt_subtest("coherency-unsync")
+		test_coherency(fd, count);
+
+	igt_subtest("dmabuf-unsync")
+		test_dmabuf();
+
+	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
+		igt_subtest_f("forked-unsync%s%s%s-%s",
+		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
+		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
+		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
+				"-mempressure" : "",
+		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
+				"interruptible" : "normal") {
+			test_forking_evictions(fd, size, count, flags);
+		}
+	}
+
+	igt_subtest("swapping-unsync-normal")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-unsync-normal")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-unsync-normal") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_fixture {
+		size = sizeof(linear);
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	igt_fork_signal_helper();
+
+	igt_subtest("swapping-unsync-interruptible")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-unsync-interruptible")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-unsync-interruptible") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_stop_signal_helper();
+
+	printf("Testing synchronized mappings...\n");
+
+	igt_fixture {
+		size = sizeof(linear);
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	gem_userptr_test_synchronized();
+
+	igt_subtest("create-destroy-sync")
+		test_create_destroy(fd);
+
+	igt_subtest("sync-overlap")
+		test_overlap(fd, EINVAL);
+
+	igt_subtest("sync-unmap")
+		test_unmap(fd, EFAULT);
+
+	igt_subtest("sync-unmap-cycles")
+		test_unmap_cycles(fd, EFAULT);
+
+	igt_subtest("sync-unmap-after-close")
+		test_unmap_after_close(fd);
+
+	igt_subtest("coherency-sync")
+		test_coherency(fd, count);
+
+	igt_subtest("dmabuf-sync")
+		test_dmabuf();
+
+	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
+		igt_subtest_f("forked-sync%s%s%s-%s",
+		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
+		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
+		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
+				"-mempressure" : "",
+		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
+				"interruptible" : "normal") {
+			test_forking_evictions(fd, size, count, flags);
+		}
+	}
+
+	igt_subtest("swapping-normal-sync")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-normal-sync")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-normal-sync") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_fixture {
+		size = 1024 * 1024;
+		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
+		if (count > total_ram * 3 / 4)
+			count = intel_get_total_ram_mb() * 3 / 4;
+	}
+
+	igt_fork_signal_helper();
+
+	igt_subtest("swapping-sync-interruptible")
+		test_swapping_evictions(fd, size, count);
+
+	igt_subtest("minor-sync-interruptible")
+		test_minor_evictions(fd, size, count);
+
+	igt_subtest("major-sync-interruptible") {
+		size = 200 * 1024 * 1024;
+		count = (gem_aperture_size(fd) / size) + 2;
+		test_major_evictions(fd, size, count);
+	}
+
+	igt_stop_signal_helper();
+
+	igt_subtest("access-control")
+	test_access_control(fd);
+
+	igt_exit();
+
+	return 0;
+}
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case
  2014-04-23 16:38 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
@ 2014-04-23 16:38   ` Tvrtko Ursulin
  2014-04-23 17:12     ` Volkin, Bradley D
  2014-04-23 16:38   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
  2014-04-23 17:24   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Volkin, Bradley D
  2 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-04-23 16:38 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

No need for the old test case once the new one was added.

v2:
   * Just rebase for lib/ reorganization.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 tests/.gitignore       |   1 -
 tests/Makefile.sources |   1 -
 tests/gem_vmap_blits.c | 345 -------------------------------------------------
 3 files changed, 347 deletions(-)
 delete mode 100644 tests/gem_vmap_blits.c

diff --git a/tests/.gitignore b/tests/.gitignore
index ff193bd..d192bb9 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -94,7 +94,6 @@ gem_tiled_swapping
 gem_tiling_max_stride
 gem_unfence_active_buffers
 gem_unref_active_buffers
-gem_vmap_blits
 gem_userptr_blits
 gem_wait_render_timeout
 gem_write_read_ring_switch
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 09d6aa3..57a0da2 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -120,7 +120,6 @@ TESTS_progs = \
 	gem_tiling_max_stride \
 	gem_unfence_active_buffers \
 	gem_unref_active_buffers \
-	gem_vmap_blits \
 	gem_userptr_blits \
 	gem_wait_render_timeout \
 	gen3_mixed_blits \
diff --git a/tests/gem_vmap_blits.c b/tests/gem_vmap_blits.c
deleted file mode 100644
index 430338b..0000000
--- a/tests/gem_vmap_blits.c
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright © 2009,2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- *    Eric Anholt <eric@anholt.net>
- *    Chris Wilson <chris@chris-wilson.co.uk>
- *
- */
-
-/** @file gem_vmap_blits.c
- *
- * This is a test of doing many blits using a mixture of normal system pages
- * and uncached linear buffers, with a working set larger than the
- * aperture size.
- *
- * The goal is to simply ensure the basics work.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#include "drm.h"
-#include "ioctl_wrappers.h"
-#include "drmtest.h"
-#include "intel_bufmgr.h"
-#include "intel_batchbuffer.h"
-#include "intel_io.h"
-
-#if !defined(I915_PARAM_HAS_VMAP)
-#pragma message("No vmap support in drm, skipping")
-int main(int argc, char **argv)
-{
-	fprintf(stderr, "No vmap support in drm.\n");
-	return 77;
-}
-#else
-
-#define WIDTH 512
-#define HEIGHT 512
-
-static uint32_t linear[WIDTH*HEIGHT];
-
-static uint32_t gem_vmap(int fd, void *ptr, int size, int read_only)
-{
-	struct drm_i915_gem_vmap vmap;
-
-	vmap.user_ptr = (uintptr_t)ptr;
-	vmap.user_size = size;
-	vmap.flags = 0;
-	if (read_only)
-		vmap.flags |= I915_VMAP_READ_ONLY;
-
-	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_VMAP, &vmap))
-		return 0;
-
-	return vmap.handle;
-}
-
-
-static void gem_vmap_sync(int fd, uint32_t handle)
-{
-	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
-}
-
-static void
-copy(int fd, uint32_t dst, uint32_t src)
-{
-	uint32_t batch[10];
-	struct drm_i915_gem_relocation_entry reloc[2];
-	struct drm_i915_gem_exec_object2 obj[3];
-	struct drm_i915_gem_execbuffer2 exec;
-	uint32_t handle;
-	int ret;
-
-	batch[0] = XY_SRC_COPY_BLT_CMD |
-		  XY_SRC_COPY_BLT_WRITE_ALPHA |
-		  XY_SRC_COPY_BLT_WRITE_RGB | 6;
-	batch[1] = (3 << 24) | /* 32 bits */
-		  (0xcc << 16) | /* copy ROP */
-		  WIDTH*4;
-	batch[2] = 0; /* dst x1,y1 */
-	batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
-	batch[4] = 0; /* dst reloc */
-	batch[5] = 0; /* src x1,y1 */
-	batch[6] = WIDTH*4;
-	batch[7] = 0; /* src reloc */
-	batch[8] = MI_BATCH_BUFFER_END;
-	batch[9] = MI_NOOP;
-
-	handle = gem_create(fd, 4096);
-	gem_write(fd, handle, 0, batch, sizeof(batch));
-
-	reloc[0].target_handle = dst;
-	reloc[0].delta = 0;
-	reloc[0].offset = 4 * sizeof(batch[0]);
-	reloc[0].presumed_offset = 0;
-	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
-	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
-
-	reloc[1].target_handle = src;
-	reloc[1].delta = 0;
-	reloc[1].offset = 7 * sizeof(batch[0]);
-	reloc[1].presumed_offset = 0;
-	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
-	reloc[1].write_domain = 0;
-
-	obj[0].handle = dst;
-	obj[0].relocation_count = 0;
-	obj[0].relocs_ptr = 0;
-	obj[0].alignment = 0;
-	obj[0].offset = 0;
-	obj[0].flags = 0;
-	obj[0].rsvd1 = 0;
-	obj[0].rsvd2 = 0;
-
-	obj[1].handle = src;
-	obj[1].relocation_count = 0;
-	obj[1].relocs_ptr = 0;
-	obj[1].alignment = 0;
-	obj[1].offset = 0;
-	obj[1].flags = 0;
-	obj[1].rsvd1 = 0;
-	obj[1].rsvd2 = 0;
-
-	obj[2].handle = handle;
-	obj[2].relocation_count = 2;
-	obj[2].relocs_ptr = (uintptr_t)reloc;
-	obj[2].alignment = 0;
-	obj[2].offset = 0;
-	obj[2].flags = 0;
-	obj[2].rsvd1 = obj[2].rsvd2 = 0;
-
-	exec.buffers_ptr = (uintptr_t)obj;
-	exec.buffer_count = 3;
-	exec.batch_start_offset = 0;
-	exec.batch_len = sizeof(batch);
-	exec.DR1 = exec.DR4 = 0;
-	exec.num_cliprects = 0;
-	exec.cliprects_ptr = 0;
-	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
-	exec.rsvd1 = exec.rsvd2 = 0;
-
-	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
-	while (ret && errno == EBUSY) {
-		drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
-		ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
-	}
-	igt_assert(ret == 0);
-
-	gem_close(fd, handle);
-}
-
-static uint32_t
-create_vmap(int fd, uint32_t val, uint32_t *ptr)
-{
-	uint32_t handle;
-	int i;
-
-	handle = gem_vmap(fd, ptr, sizeof(linear), 0);
-
-	/* Fill the BO with dwords starting at val */
-	for (i = 0; i < WIDTH*HEIGHT; i++)
-		ptr[i] = val++;
-
-	return handle;
-}
-
-static uint32_t
-create_bo(int fd, uint32_t val)
-{
-	uint32_t handle;
-	int i;
-
-	handle = gem_create(fd, sizeof(linear));
-
-	/* Fill the BO with dwords starting at val */
-	for (i = 0; i < WIDTH*HEIGHT; i++)
-		linear[i] = val++;
-	gem_write(fd, handle, 0, linear, sizeof(linear));
-
-	return handle;
-}
-
-static void
-check_cpu(uint32_t *ptr, uint32_t val)
-{
-	int i;
-
-	for (i = 0; i < WIDTH*HEIGHT; i++) {
-		if (ptr[i] != val) {
-			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
-				"at offset 0x%08x\n",
-				val, ptr[i], i * 4);
-			abort();
-		}
-		val++;
-	}
-}
-
-static void
-check_gpu(int fd, uint32_t handle, uint32_t val)
-{
-	gem_read(fd, handle, 0, linear, sizeof(linear));
-	check_cpu(linear, val);
-}
-
-static int has_vmap(int fd)
-{
-	drm_i915_getparam_t gp;
-	int i;
-
-	gp.param = I915_PARAM_HAS_VMAP;
-	gp.value = &i;
-
-	return drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0 && i > 0;
-}
-
-int main(int argc, char **argv)
-{
-	uint32_t *memory;
-	uint32_t *cpu, *cpu_val;
-	uint32_t *gpu, *gpu_val;
-	uint32_t start = 0;
-	int i, fd, count;
-
-	igt_simple_init();
-
-	igt_skip_on_simulation();
-
-	fd = drm_open_any();
-
-	if (!has_vmap(fd)) {
-		fprintf(stderr, "No vmap support, ignoring.\n");
-		return 77;
-	}
-
-	count = 0;
-	if (argc > 1)
-		count = atoi(argv[1]);
-	if (count == 0)
-		count = 3 * gem_aperture_size(fd) / (1024*1024) / 4;
-	printf("Using 2x%d 1MiB buffers\n", count);
-
-	memory = malloc(count*sizeof(linear));
-	if (memory == NULL) {
-		fprintf(stderr, "Unable to allocate %lld bytes\n",
-			(long long)count*sizeof(linear));
-		return 1;
-	}
-
-	gpu = malloc(sizeof(uint32_t)*count*4);
-	gpu_val = gpu + count;
-	cpu = gpu_val + count;
-	cpu_val = cpu + count;
-
-	for (i = 0; i < count; i++) {
-		gpu[i] = create_bo(fd, start);
-		gpu_val[i] = start;
-		start += WIDTH*HEIGHT;
-	}
-
-	for (i = 0; i < count; i++) {
-		cpu[i] = create_vmap(fd, start, memory+i*WIDTH*HEIGHT);
-		cpu_val[i] = start;
-		start += WIDTH*HEIGHT;;
-	}
-
-	printf("Verifying initialisation...\n");
-	for (i = 0; i < count; i++) {
-		check_gpu(fd, gpu[i], gpu_val[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	printf("Cyclic blits cpu->gpu, forward...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = i % count;
-		int dst = (i + 1) % count;
-
-		copy(fd, gpu[dst], cpu[src]);
-		gpu_val[dst] = cpu_val[src];
-	}
-	for (i = 0; i < count; i++)
-		check_gpu(fd, gpu[i], gpu_val[i]);
-
-	printf("Cyclic blits gpu->cpu, backward...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = (i + 1) % count;
-		int dst = i % count;
-
-		copy(fd, cpu[dst], gpu[src]);
-		cpu_val[dst] = gpu_val[src];
-	}
-	for (i = 0; i < count; i++) {
-		gem_vmap_sync(fd, cpu[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	printf("Random blits...\n");
-	for (i = 0; i < count * 4; i++) {
-		int src = random() % count;
-		int dst = random() % count;
-
-		if (random() & 1) {
-			copy(fd, gpu[dst], cpu[src]);
-			gpu_val[dst] = cpu_val[src];
-		} else {
-			copy(fd, cpu[dst], gpu[src]);
-			cpu_val[dst] = gpu_val[src];
-		}
-	}
-	for (i = 0; i < count; i++) {
-		check_gpu(fd, gpu[i], gpu_val[i]);
-		gem_vmap_sync(fd, cpu[i]);
-		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
-	}
-
-	return 0;
-}
-
-#endif
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-04-23 16:38 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
  2014-04-23 16:38   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
@ 2014-04-23 16:38   ` Tvrtko Ursulin
  2014-04-23 17:17     ` Volkin, Bradley D
  2014-04-23 17:24   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Volkin, Bradley D
  2 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-04-23 16:38 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This adds a small benchmark for the new userptr functionality.

Apart from basic surface creation and destruction, also tested is the
impact of having userptr surfaces in the process address space. Reason
for that is the impact of MMU notifiers on common address space
operations like munmap() which is per process.

v2:
  * Moved to benchmarks.
  * Added pointer read/write tests.
  * Changed output to say iterations per second instead of
    operations per second.
  * Multiply result by batch size for multi-create* tests
    for a more comparable number with create-destroy test.

v3:
  * Use ALIGN macro.
  * Catchup with big lib/ reorganization.
  * Removed unused code and one global variable.
  * Fixed up some warnings.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
---
 benchmarks/.gitignore              |   1 +
 benchmarks/Makefile.sources        |   3 +-
 benchmarks/gem_userptr_benchmark.c | 497 +++++++++++++++++++++++++++++++++++++
 3 files changed, 500 insertions(+), 1 deletion(-)
 create mode 100644 benchmarks/gem_userptr_benchmark.c

diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
index ddea6f7..09e5bd8 100644
--- a/benchmarks/.gitignore
+++ b/benchmarks/.gitignore
@@ -1,3 +1,4 @@
+gem_userptr_benchmark
 intel_upload_blit_large
 intel_upload_blit_large_gtt
 intel_upload_blit_large_map
diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
index f9da579..60bdae2 100644
--- a/benchmarks/Makefile.sources
+++ b/benchmarks/Makefile.sources
@@ -2,4 +2,5 @@ bin_PROGRAMS =                          \
 	intel_upload_blit_large         \
 	intel_upload_blit_large_gtt     \
 	intel_upload_blit_large_map     \
-	intel_upload_blit_small
+	intel_upload_blit_small		\
+	gem_userptr_benchmark
diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
new file mode 100644
index 0000000..a51201c
--- /dev/null
+++ b/benchmarks/gem_userptr_benchmark.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+ *
+ */
+
+/** @file gem_userptr_benchmark.c
+ *
+ * Benchmark the userptr code and impact of having userptr surfaces
+ * in process address space on some normal operations.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_chipset.h"
+#include "ioctl_wrappers.h"
+#include "igt_aux.h"
+
+#ifndef PAGE_SIZE
+  #define PAGE_SIZE 4096
+#endif
+
+#define LOCAL_I915_GEM_USERPTR       0x34
+#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
+struct local_i915_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint32_t flags;
+#define LOCAL_I915_USERPTR_READ_ONLY (1<<0)
+#define LOCAL_I915_USERPTR_UNSYNCHRONIZED (1<<31)
+	uint32_t handle;
+};
+
+static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+
+#define BO_SIZE (65536)
+
+static void gem_userptr_test_unsynchronized(void)
+{
+	userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+}
+
+static void gem_userptr_test_synchronized(void)
+{
+	userptr_flags = 0;
+}
+
+static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	userptr.user_ptr = (uintptr_t)ptr;
+	userptr.user_size = size;
+	userptr.flags = userptr_flags;
+	if (read_only)
+		userptr.flags |= LOCAL_I915_USERPTR_READ_ONLY;
+
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	if (ret)
+		ret = errno;
+	igt_skip_on_f(ret == ENODEV &&
+		      (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) == 0,
+		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
+	if (ret == 0)
+		*handle = userptr.handle;
+
+	return ret;
+}
+
+static void **handle_ptr_map;
+static unsigned int num_handle_ptr_map;
+
+static void add_handle_ptr(uint32_t handle, void *ptr)
+{
+	if (handle >= num_handle_ptr_map) {
+		handle_ptr_map = realloc(handle_ptr_map,
+					 (handle + 1000) * sizeof(void*));
+		num_handle_ptr_map = handle + 1000;
+	}
+
+	handle_ptr_map[handle] = ptr;
+}
+
+static void *get_handle_ptr(uint32_t handle)
+{
+	return handle_ptr_map[handle];
+}
+
+static void free_handle_ptr(uint32_t handle)
+{
+	igt_assert(handle < num_handle_ptr_map);
+	igt_assert(handle_ptr_map[handle]);
+
+	free(handle_ptr_map[handle]);
+	handle_ptr_map[handle] = NULL;
+}
+
+static uint32_t create_userptr_bo(int fd, int size)
+{
+	void *ptr;
+	uint32_t handle;
+	int ret;
+
+	ret = posix_memalign(&ptr, PAGE_SIZE, size);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
+	igt_assert(ret == 0);
+	add_handle_ptr(handle, ptr);
+
+	return handle;
+}
+
+static void free_userptr_bo(int fd, uint32_t handle)
+{
+	gem_close(fd, handle);
+	free_handle_ptr(handle);
+}
+
+static int has_userptr(int fd)
+{
+	uint32_t handle = 0;
+	void *ptr;
+	uint32_t oldflags;
+	int ret;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+	oldflags = userptr_flags;
+	gem_userptr_test_unsynchronized();
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	userptr_flags = oldflags;
+	if (ret != 0) {
+		free(ptr);
+		return 0;
+	}
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return handle != 0;
+}
+
+static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
+static const unsigned int test_duration_sec = 3;
+
+static volatile unsigned int run_test;
+
+static void alarm_handler(int sig)
+{
+	assert(run_test == 1);
+	run_test = 0;
+}
+
+static void start_test(unsigned int duration)
+{
+	run_test = 1;
+	if (duration == 0)
+		duration = test_duration_sec;
+	signal(SIGALRM, alarm_handler);
+	alarm(duration);
+}
+
+static void exchange_ptr(void *array, unsigned i, unsigned j)
+{
+	void **arr, *tmp;
+	arr = (void **)array;
+
+	tmp = arr[i];
+	arr[i] = arr[j];
+	arr[j] = tmp;
+}
+
+static void test_malloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_malloc_realloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++) {
+			ptr[i] = realloc(ptr[i], 2000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_mmap_unmap(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
+					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+			assert(ptr[i] != MAP_FAILED);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			munmap(ptr[i], 1000);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_ptr_read(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	unsigned long i, loops;
+	register unsigned long v;
+
+	loops = BO_SIZE / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			v = *p++;
+			v = *p++;
+			v = *p++;
+			v = *p++;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
+}
+
+static void test_ptr_write(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	register unsigned long i, loops;
+
+	loops = BO_SIZE / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
+}
+
+static void test_impact(int fd)
+{
+	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
+	unsigned int subtest, i;
+	uint32_t handles[nr_bos[total-1]];
+	void *ptr;
+	char buffer[BO_SIZE];
+
+	for (subtest = 0; subtest < total; subtest++) {
+		for (i = 0; i < nr_bos[subtest]; i++)
+			handles[i] = create_userptr_bo(fd, BO_SIZE);
+
+		if (nr_bos[subtest] > 0)
+			ptr = get_handle_ptr(handles[0]);
+		else
+			ptr = buffer;
+
+		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_read(ptr);
+
+		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_write(ptr);
+
+		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(0);
+		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(1);
+
+		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(0);
+		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(1);
+
+		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(0);
+		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(1);
+
+		for (i = 0; i < nr_bos[subtest]; i++)
+			free_userptr_bo(fd, handles[i]);
+	}
+}
+
+static void test_single(int fd)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handle = 0;
+	unsigned long iter = 0;
+	int ret;
+	unsigned long map_size = BO_SIZE + PAGE_SIZE - 1;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		ret = gem_userptr(fd, bo_ptr, BO_SIZE, 0, &handle);
+		assert(ret == 0);
+		gem_close(fd, handle);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_multiple(int fd, unsigned int batch, int random)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handles[10000];
+	int map[10000];
+	unsigned long iter = 0;
+	int ret;
+	int i;
+	unsigned long map_size = batch * BO_SIZE + PAGE_SIZE - 1;
+
+	assert(batch < (sizeof(handles) / sizeof(handles[0])));
+	assert(batch < (sizeof(map) / sizeof(map[0])));
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
+
+	for (i = 0; i < batch; i++)
+		map[i] = i;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++) {
+			ret = gem_userptr(fd, bo_ptr + map[i] * BO_SIZE,
+						BO_SIZE,
+						0, &handles[i]);
+			assert(ret == 0);
+		}
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++)
+			gem_close(fd, handles[map[i]]);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter * batch / test_duration_sec);
+}
+
+static void test_userptr(int fd)
+{
+	printf("create-destroy                = ");
+	test_single(fd);
+
+	printf("multi-create-destroy          = ");
+	test_multiple(fd, 100, 0);
+
+	printf("multi-create-destroy-random   = ");
+	test_multiple(fd, 100, 1);
+}
+
+int main(int argc, char **argv)
+{
+	int fd = -1, ret;
+
+	igt_skip_on_simulation();
+
+	igt_subtest_init(argc, argv);
+
+	fd = drm_open_any();
+	igt_assert(fd >= 0);
+
+	ret = has_userptr(fd);
+	igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
+			strerror(errno), ret);
+
+
+	gem_userptr_test_unsynchronized();
+
+	igt_subtest("userptr-unsync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-unsync")
+		test_impact(fd);
+
+	gem_userptr_test_synchronized();
+
+	igt_subtest("userptr-sync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-sync")
+		test_impact(fd);
+
+	igt_exit();
+
+	return 0;
+}
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case
  2014-04-23 16:38   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
@ 2014-04-23 17:12     ` Volkin, Bradley D
  0 siblings, 0 replies; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-23 17:12 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

Reviewed-by: Brad Volkin <bradley.d.volkin@intel.com>

On Wed, Apr 23, 2014 at 05:38:34PM +0100, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> No need for the old test case once the new one was added.
> 
> v2:
>    * Just rebase for lib/ reorganization.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>  tests/.gitignore       |   1 -
>  tests/Makefile.sources |   1 -
>  tests/gem_vmap_blits.c | 345 -------------------------------------------------
>  3 files changed, 347 deletions(-)
>  delete mode 100644 tests/gem_vmap_blits.c
> 
> diff --git a/tests/.gitignore b/tests/.gitignore
> index ff193bd..d192bb9 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -94,7 +94,6 @@ gem_tiled_swapping
>  gem_tiling_max_stride
>  gem_unfence_active_buffers
>  gem_unref_active_buffers
> -gem_vmap_blits
>  gem_userptr_blits
>  gem_wait_render_timeout
>  gem_write_read_ring_switch
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index 09d6aa3..57a0da2 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -120,7 +120,6 @@ TESTS_progs = \
>  	gem_tiling_max_stride \
>  	gem_unfence_active_buffers \
>  	gem_unref_active_buffers \
> -	gem_vmap_blits \
>  	gem_userptr_blits \
>  	gem_wait_render_timeout \
>  	gen3_mixed_blits \
> diff --git a/tests/gem_vmap_blits.c b/tests/gem_vmap_blits.c
> deleted file mode 100644
> index 430338b..0000000
> --- a/tests/gem_vmap_blits.c
> +++ /dev/null
> @@ -1,345 +0,0 @@
> -/*
> - * Copyright © 2009,2011 Intel Corporation
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> - *
> - * Authors:
> - *    Eric Anholt <eric@anholt.net>
> - *    Chris Wilson <chris@chris-wilson.co.uk>
> - *
> - */
> -
> -/** @file gem_vmap_blits.c
> - *
> - * This is a test of doing many blits using a mixture of normal system pages
> - * and uncached linear buffers, with a working set larger than the
> - * aperture size.
> - *
> - * The goal is to simply ensure the basics work.
> - */
> -
> -#include <stdlib.h>
> -#include <stdio.h>
> -#include <string.h>
> -#include <fcntl.h>
> -#include <inttypes.h>
> -#include <errno.h>
> -#include <sys/stat.h>
> -#include <sys/time.h>
> -
> -#include "drm.h"
> -#include "ioctl_wrappers.h"
> -#include "drmtest.h"
> -#include "intel_bufmgr.h"
> -#include "intel_batchbuffer.h"
> -#include "intel_io.h"
> -
> -#if !defined(I915_PARAM_HAS_VMAP)
> -#pragma message("No vmap support in drm, skipping")
> -int main(int argc, char **argv)
> -{
> -	fprintf(stderr, "No vmap support in drm.\n");
> -	return 77;
> -}
> -#else
> -
> -#define WIDTH 512
> -#define HEIGHT 512
> -
> -static uint32_t linear[WIDTH*HEIGHT];
> -
> -static uint32_t gem_vmap(int fd, void *ptr, int size, int read_only)
> -{
> -	struct drm_i915_gem_vmap vmap;
> -
> -	vmap.user_ptr = (uintptr_t)ptr;
> -	vmap.user_size = size;
> -	vmap.flags = 0;
> -	if (read_only)
> -		vmap.flags |= I915_VMAP_READ_ONLY;
> -
> -	if (drmIoctl(fd, DRM_IOCTL_I915_GEM_VMAP, &vmap))
> -		return 0;
> -
> -	return vmap.handle;
> -}
> -
> -
> -static void gem_vmap_sync(int fd, uint32_t handle)
> -{
> -	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> -}
> -
> -static void
> -copy(int fd, uint32_t dst, uint32_t src)
> -{
> -	uint32_t batch[10];
> -	struct drm_i915_gem_relocation_entry reloc[2];
> -	struct drm_i915_gem_exec_object2 obj[3];
> -	struct drm_i915_gem_execbuffer2 exec;
> -	uint32_t handle;
> -	int ret;
> -
> -	batch[0] = XY_SRC_COPY_BLT_CMD |
> -		  XY_SRC_COPY_BLT_WRITE_ALPHA |
> -		  XY_SRC_COPY_BLT_WRITE_RGB | 6;
> -	batch[1] = (3 << 24) | /* 32 bits */
> -		  (0xcc << 16) | /* copy ROP */
> -		  WIDTH*4;
> -	batch[2] = 0; /* dst x1,y1 */
> -	batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
> -	batch[4] = 0; /* dst reloc */
> -	batch[5] = 0; /* src x1,y1 */
> -	batch[6] = WIDTH*4;
> -	batch[7] = 0; /* src reloc */
> -	batch[8] = MI_BATCH_BUFFER_END;
> -	batch[9] = MI_NOOP;
> -
> -	handle = gem_create(fd, 4096);
> -	gem_write(fd, handle, 0, batch, sizeof(batch));
> -
> -	reloc[0].target_handle = dst;
> -	reloc[0].delta = 0;
> -	reloc[0].offset = 4 * sizeof(batch[0]);
> -	reloc[0].presumed_offset = 0;
> -	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
> -	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
> -
> -	reloc[1].target_handle = src;
> -	reloc[1].delta = 0;
> -	reloc[1].offset = 7 * sizeof(batch[0]);
> -	reloc[1].presumed_offset = 0;
> -	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
> -	reloc[1].write_domain = 0;
> -
> -	obj[0].handle = dst;
> -	obj[0].relocation_count = 0;
> -	obj[0].relocs_ptr = 0;
> -	obj[0].alignment = 0;
> -	obj[0].offset = 0;
> -	obj[0].flags = 0;
> -	obj[0].rsvd1 = 0;
> -	obj[0].rsvd2 = 0;
> -
> -	obj[1].handle = src;
> -	obj[1].relocation_count = 0;
> -	obj[1].relocs_ptr = 0;
> -	obj[1].alignment = 0;
> -	obj[1].offset = 0;
> -	obj[1].flags = 0;
> -	obj[1].rsvd1 = 0;
> -	obj[1].rsvd2 = 0;
> -
> -	obj[2].handle = handle;
> -	obj[2].relocation_count = 2;
> -	obj[2].relocs_ptr = (uintptr_t)reloc;
> -	obj[2].alignment = 0;
> -	obj[2].offset = 0;
> -	obj[2].flags = 0;
> -	obj[2].rsvd1 = obj[2].rsvd2 = 0;
> -
> -	exec.buffers_ptr = (uintptr_t)obj;
> -	exec.buffer_count = 3;
> -	exec.batch_start_offset = 0;
> -	exec.batch_len = sizeof(batch);
> -	exec.DR1 = exec.DR4 = 0;
> -	exec.num_cliprects = 0;
> -	exec.cliprects_ptr = 0;
> -	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
> -	exec.rsvd1 = exec.rsvd2 = 0;
> -
> -	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> -	while (ret && errno == EBUSY) {
> -		drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
> -		ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> -	}
> -	igt_assert(ret == 0);
> -
> -	gem_close(fd, handle);
> -}
> -
> -static uint32_t
> -create_vmap(int fd, uint32_t val, uint32_t *ptr)
> -{
> -	uint32_t handle;
> -	int i;
> -
> -	handle = gem_vmap(fd, ptr, sizeof(linear), 0);
> -
> -	/* Fill the BO with dwords starting at val */
> -	for (i = 0; i < WIDTH*HEIGHT; i++)
> -		ptr[i] = val++;
> -
> -	return handle;
> -}
> -
> -static uint32_t
> -create_bo(int fd, uint32_t val)
> -{
> -	uint32_t handle;
> -	int i;
> -
> -	handle = gem_create(fd, sizeof(linear));
> -
> -	/* Fill the BO with dwords starting at val */
> -	for (i = 0; i < WIDTH*HEIGHT; i++)
> -		linear[i] = val++;
> -	gem_write(fd, handle, 0, linear, sizeof(linear));
> -
> -	return handle;
> -}
> -
> -static void
> -check_cpu(uint32_t *ptr, uint32_t val)
> -{
> -	int i;
> -
> -	for (i = 0; i < WIDTH*HEIGHT; i++) {
> -		if (ptr[i] != val) {
> -			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
> -				"at offset 0x%08x\n",
> -				val, ptr[i], i * 4);
> -			abort();
> -		}
> -		val++;
> -	}
> -}
> -
> -static void
> -check_gpu(int fd, uint32_t handle, uint32_t val)
> -{
> -	gem_read(fd, handle, 0, linear, sizeof(linear));
> -	check_cpu(linear, val);
> -}
> -
> -static int has_vmap(int fd)
> -{
> -	drm_i915_getparam_t gp;
> -	int i;
> -
> -	gp.param = I915_PARAM_HAS_VMAP;
> -	gp.value = &i;
> -
> -	return drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0 && i > 0;
> -}
> -
> -int main(int argc, char **argv)
> -{
> -	uint32_t *memory;
> -	uint32_t *cpu, *cpu_val;
> -	uint32_t *gpu, *gpu_val;
> -	uint32_t start = 0;
> -	int i, fd, count;
> -
> -	igt_simple_init();
> -
> -	igt_skip_on_simulation();
> -
> -	fd = drm_open_any();
> -
> -	if (!has_vmap(fd)) {
> -		fprintf(stderr, "No vmap support, ignoring.\n");
> -		return 77;
> -	}
> -
> -	count = 0;
> -	if (argc > 1)
> -		count = atoi(argv[1]);
> -	if (count == 0)
> -		count = 3 * gem_aperture_size(fd) / (1024*1024) / 4;
> -	printf("Using 2x%d 1MiB buffers\n", count);
> -
> -	memory = malloc(count*sizeof(linear));
> -	if (memory == NULL) {
> -		fprintf(stderr, "Unable to allocate %lld bytes\n",
> -			(long long)count*sizeof(linear));
> -		return 1;
> -	}
> -
> -	gpu = malloc(sizeof(uint32_t)*count*4);
> -	gpu_val = gpu + count;
> -	cpu = gpu_val + count;
> -	cpu_val = cpu + count;
> -
> -	for (i = 0; i < count; i++) {
> -		gpu[i] = create_bo(fd, start);
> -		gpu_val[i] = start;
> -		start += WIDTH*HEIGHT;
> -	}
> -
> -	for (i = 0; i < count; i++) {
> -		cpu[i] = create_vmap(fd, start, memory+i*WIDTH*HEIGHT);
> -		cpu_val[i] = start;
> -		start += WIDTH*HEIGHT;;
> -	}
> -
> -	printf("Verifying initialisation...\n");
> -	for (i = 0; i < count; i++) {
> -		check_gpu(fd, gpu[i], gpu_val[i]);
> -		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> -	}
> -
> -	printf("Cyclic blits cpu->gpu, forward...\n");
> -	for (i = 0; i < count * 4; i++) {
> -		int src = i % count;
> -		int dst = (i + 1) % count;
> -
> -		copy(fd, gpu[dst], cpu[src]);
> -		gpu_val[dst] = cpu_val[src];
> -	}
> -	for (i = 0; i < count; i++)
> -		check_gpu(fd, gpu[i], gpu_val[i]);
> -
> -	printf("Cyclic blits gpu->cpu, backward...\n");
> -	for (i = 0; i < count * 4; i++) {
> -		int src = (i + 1) % count;
> -		int dst = i % count;
> -
> -		copy(fd, cpu[dst], gpu[src]);
> -		cpu_val[dst] = gpu_val[src];
> -	}
> -	for (i = 0; i < count; i++) {
> -		gem_vmap_sync(fd, cpu[i]);
> -		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> -	}
> -
> -	printf("Random blits...\n");
> -	for (i = 0; i < count * 4; i++) {
> -		int src = random() % count;
> -		int dst = random() % count;
> -
> -		if (random() & 1) {
> -			copy(fd, gpu[dst], cpu[src]);
> -			gpu_val[dst] = cpu_val[src];
> -		} else {
> -			copy(fd, cpu[dst], gpu[src]);
> -			cpu_val[dst] = gpu_val[src];
> -		}
> -	}
> -	for (i = 0; i < count; i++) {
> -		check_gpu(fd, gpu[i], gpu_val[i]);
> -		gem_vmap_sync(fd, cpu[i]);
> -		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> -	}
> -
> -	return 0;
> -}
> -
> -#endif
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-04-23 16:38   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
@ 2014-04-23 17:17     ` Volkin, Bradley D
  2014-04-24  9:08       ` Tvrtko Ursulin
  0 siblings, 1 reply; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-23 17:17 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

On Wed, Apr 23, 2014 at 05:38:35PM +0100, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> This adds a small benchmark for the new userptr functionality.
> 
> Apart from basic surface creation and destruction, also tested is the
> impact of having userptr surfaces in the process address space. Reason
> for that is the impact of MMU notifiers on common address space
> operations like munmap() which is per process.
> 
> v2:
>   * Moved to benchmarks.
>   * Added pointer read/write tests.
>   * Changed output to say iterations per second instead of
>     operations per second.
>   * Multiply result by batch size for multi-create* tests
>     for a more comparable number with create-destroy test.
> 
> v3:
>   * Use ALIGN macro.
>   * Catchup with big lib/ reorganization.
>   * Removed unused code and one global variable.
>   * Fixed up some warnings.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  benchmarks/.gitignore              |   1 +
>  benchmarks/Makefile.sources        |   3 +-
>  benchmarks/gem_userptr_benchmark.c | 497 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 500 insertions(+), 1 deletion(-)
>  create mode 100644 benchmarks/gem_userptr_benchmark.c
> 
> diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
> index ddea6f7..09e5bd8 100644
> --- a/benchmarks/.gitignore
> +++ b/benchmarks/.gitignore
> @@ -1,3 +1,4 @@
> +gem_userptr_benchmark
>  intel_upload_blit_large
>  intel_upload_blit_large_gtt
>  intel_upload_blit_large_map
> diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
> index f9da579..60bdae2 100644
> --- a/benchmarks/Makefile.sources
> +++ b/benchmarks/Makefile.sources
> @@ -2,4 +2,5 @@ bin_PROGRAMS =                          \
>  	intel_upload_blit_large         \
>  	intel_upload_blit_large_gtt     \
>  	intel_upload_blit_large_map     \
> -	intel_upload_blit_small
> +	intel_upload_blit_small		\
> +	gem_userptr_benchmark
> diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
> new file mode 100644
> index 0000000..a51201c
> --- /dev/null
> +++ b/benchmarks/gem_userptr_benchmark.c
> @@ -0,0 +1,497 @@
> +/*
> + * Copyright © 2014 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> + *
> + */
> +
> +/** @file gem_userptr_benchmark.c
> + *
> + * Benchmark the userptr code and impact of having userptr surfaces
> + * in process address space on some normal operations.
> + *
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <assert.h>
> +#include <sys/stat.h>
> +#include <sys/time.h>
> +#include <sys/mman.h>
> +#include "drm.h"
> +#include "i915_drm.h"
> +#include "drmtest.h"
> +#include "intel_bufmgr.h"
> +#include "intel_batchbuffer.h"
> +#include "intel_chipset.h"
> +#include "ioctl_wrappers.h"
> +#include "igt_aux.h"
> +
> +#ifndef PAGE_SIZE
> +  #define PAGE_SIZE 4096
> +#endif
> +
> +#define LOCAL_I915_GEM_USERPTR       0x34
> +#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
> +struct local_i915_gem_userptr {
> +	uint64_t user_ptr;
> +	uint64_t user_size;
> +	uint32_t flags;
> +#define LOCAL_I915_USERPTR_READ_ONLY (1<<0)
> +#define LOCAL_I915_USERPTR_UNSYNCHRONIZED (1<<31)
> +	uint32_t handle;
> +};
> +
> +static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
> +
> +#define BO_SIZE (65536)
> +
> +static void gem_userptr_test_unsynchronized(void)
> +{
> +	userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
> +}
> +
> +static void gem_userptr_test_synchronized(void)
> +{
> +	userptr_flags = 0;
> +}
> +
> +static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
> +{
> +	struct local_i915_gem_userptr userptr;
> +	int ret;
> +
> +	userptr.user_ptr = (uintptr_t)ptr;
> +	userptr.user_size = size;
> +	userptr.flags = userptr_flags;
> +	if (read_only)
> +		userptr.flags |= LOCAL_I915_USERPTR_READ_ONLY;
> +
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	if (ret)
> +		ret = errno;
> +	igt_skip_on_f(ret == ENODEV &&
> +		      (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) == 0,
> +		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");

I missed it the first time around, but the condition here doesn't
match the other test; it's missing the '&& !read_only'. It looks
like read_only will always be 0 in this test though, so probably
not an issue.

Reviewed-by: Brad Volkin <bradley.d.volkin@intel.com>

> +	if (ret == 0)
> +		*handle = userptr.handle;
> +
> +	return ret;
> +}
> +
> +static void **handle_ptr_map;
> +static unsigned int num_handle_ptr_map;
> +
> +static void add_handle_ptr(uint32_t handle, void *ptr)
> +{
> +	if (handle >= num_handle_ptr_map) {
> +		handle_ptr_map = realloc(handle_ptr_map,
> +					 (handle + 1000) * sizeof(void*));
> +		num_handle_ptr_map = handle + 1000;
> +	}
> +
> +	handle_ptr_map[handle] = ptr;
> +}
> +
> +static void *get_handle_ptr(uint32_t handle)
> +{
> +	return handle_ptr_map[handle];
> +}
> +
> +static void free_handle_ptr(uint32_t handle)
> +{
> +	igt_assert(handle < num_handle_ptr_map);
> +	igt_assert(handle_ptr_map[handle]);
> +
> +	free(handle_ptr_map[handle]);
> +	handle_ptr_map[handle] = NULL;
> +}
> +
> +static uint32_t create_userptr_bo(int fd, int size)
> +{
> +	void *ptr;
> +	uint32_t handle;
> +	int ret;
> +
> +	ret = posix_memalign(&ptr, PAGE_SIZE, size);
> +	igt_assert(ret == 0);
> +
> +	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
> +	igt_assert(ret == 0);
> +	add_handle_ptr(handle, ptr);
> +
> +	return handle;
> +}
> +
> +static void free_userptr_bo(int fd, uint32_t handle)
> +{
> +	gem_close(fd, handle);
> +	free_handle_ptr(handle);
> +}
> +
> +static int has_userptr(int fd)
> +{
> +	uint32_t handle = 0;
> +	void *ptr;
> +	uint32_t oldflags;
> +	int ret;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +	oldflags = userptr_flags;
> +	gem_userptr_test_unsynchronized();
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	userptr_flags = oldflags;
> +	if (ret != 0) {
> +		free(ptr);
> +		return 0;
> +	}
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return handle != 0;
> +}
> +
> +static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
> +static const unsigned int test_duration_sec = 3;
> +
> +static volatile unsigned int run_test;
> +
> +static void alarm_handler(int sig)
> +{
> +	assert(run_test == 1);
> +	run_test = 0;
> +}
> +
> +static void start_test(unsigned int duration)
> +{
> +	run_test = 1;
> +	if (duration == 0)
> +		duration = test_duration_sec;
> +	signal(SIGALRM, alarm_handler);
> +	alarm(duration);
> +}
> +
> +static void exchange_ptr(void *array, unsigned i, unsigned j)
> +{
> +	void **arr, *tmp;
> +	arr = (void **)array;
> +
> +	tmp = arr[i];
> +	arr[i] = arr[j];
> +	arr[j] = tmp;
> +}
> +
> +static void test_malloc_free(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = malloc(1000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			free(ptr[i]);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_malloc_realloc_free(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = malloc(1000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = realloc(ptr[i], 2000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			free(ptr[i]);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_mmap_unmap(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
> +					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +			assert(ptr[i] != MAP_FAILED);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			munmap(ptr[i], 1000);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_ptr_read(void *ptr)
> +{
> +	unsigned long iter = 0;
> +	volatile unsigned long *p;
> +	unsigned long i, loops;
> +	register unsigned long v;
> +
> +	loops = BO_SIZE / sizeof(unsigned long) / 4;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		p = (unsigned long *)ptr;
> +		for (i = 0; i < loops; i++) {
> +			v = *p++;
> +			v = *p++;
> +			v = *p++;
> +			v = *p++;
> +		}
> +		iter++;
> +	}
> +
> +	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
> +}
> +
> +static void test_ptr_write(void *ptr)
> +{
> +	unsigned long iter = 0;
> +	volatile unsigned long *p;
> +	register unsigned long i, loops;
> +
> +	loops = BO_SIZE / sizeof(unsigned long) / 4;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		p = (unsigned long *)ptr;
> +		for (i = 0; i < loops; i++) {
> +			*p++ = i;
> +			*p++ = i;
> +			*p++ = i;
> +			*p++ = i;
> +		}
> +		iter++;
> +	}
> +
> +	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
> +}
> +
> +static void test_impact(int fd)
> +{
> +	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
> +	unsigned int subtest, i;
> +	uint32_t handles[nr_bos[total-1]];
> +	void *ptr;
> +	char buffer[BO_SIZE];
> +
> +	for (subtest = 0; subtest < total; subtest++) {
> +		for (i = 0; i < nr_bos[subtest]; i++)
> +			handles[i] = create_userptr_bo(fd, BO_SIZE);
> +
> +		if (nr_bos[subtest] > 0)
> +			ptr = get_handle_ptr(handles[0]);
> +		else
> +			ptr = buffer;
> +
> +		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
> +		test_ptr_read(ptr);
> +
> +		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
> +		test_ptr_write(ptr);
> +
> +		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
> +		test_malloc_free(0);
> +		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
> +		test_malloc_free(1);
> +
> +		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
> +		test_malloc_realloc_free(0);
> +		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
> +		test_malloc_realloc_free(1);
> +
> +		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
> +		test_mmap_unmap(0);
> +		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
> +		test_mmap_unmap(1);
> +
> +		for (i = 0; i < nr_bos[subtest]; i++)
> +			free_userptr_bo(fd, handles[i]);
> +	}
> +}
> +
> +static void test_single(int fd)
> +{
> +	char *ptr, *bo_ptr;
> +	uint32_t handle = 0;
> +	unsigned long iter = 0;
> +	int ret;
> +	unsigned long map_size = BO_SIZE + PAGE_SIZE - 1;
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		ret = gem_userptr(fd, bo_ptr, BO_SIZE, 0, &handle);
> +		assert(ret == 0);
> +		gem_close(fd, handle);
> +		iter++;
> +	}
> +
> +	munmap(ptr, map_size);
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_multiple(int fd, unsigned int batch, int random)
> +{
> +	char *ptr, *bo_ptr;
> +	uint32_t handles[10000];
> +	int map[10000];
> +	unsigned long iter = 0;
> +	int ret;
> +	int i;
> +	unsigned long map_size = batch * BO_SIZE + PAGE_SIZE - 1;
> +
> +	assert(batch < (sizeof(handles) / sizeof(handles[0])));
> +	assert(batch < (sizeof(map) / sizeof(map[0])));
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
> +
> +	for (i = 0; i < batch; i++)
> +		map[i] = i;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		if (random)
> +			igt_permute_array(map, batch, igt_exchange_int);
> +		for (i = 0; i < batch; i++) {
> +			ret = gem_userptr(fd, bo_ptr + map[i] * BO_SIZE,
> +						BO_SIZE,
> +						0, &handles[i]);
> +			assert(ret == 0);
> +		}
> +		if (random)
> +			igt_permute_array(map, batch, igt_exchange_int);
> +		for (i = 0; i < batch; i++)
> +			gem_close(fd, handles[map[i]]);
> +		iter++;
> +	}
> +
> +	munmap(ptr, map_size);
> +
> +	printf("%8lu iter/s\n", iter * batch / test_duration_sec);
> +}
> +
> +static void test_userptr(int fd)
> +{
> +	printf("create-destroy                = ");
> +	test_single(fd);
> +
> +	printf("multi-create-destroy          = ");
> +	test_multiple(fd, 100, 0);
> +
> +	printf("multi-create-destroy-random   = ");
> +	test_multiple(fd, 100, 1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int fd = -1, ret;
> +
> +	igt_skip_on_simulation();
> +
> +	igt_subtest_init(argc, argv);
> +
> +	fd = drm_open_any();
> +	igt_assert(fd >= 0);
> +
> +	ret = has_userptr(fd);
> +	igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
> +			strerror(errno), ret);
> +
> +
> +	gem_userptr_test_unsynchronized();
> +
> +	igt_subtest("userptr-unsync")
> +		test_userptr(fd);
> +
> +	igt_subtest("userptr-impact-unsync")
> +		test_impact(fd);
> +
> +	gem_userptr_test_synchronized();
> +
> +	igt_subtest("userptr-sync")
> +		test_userptr(fd);
> +
> +	igt_subtest("userptr-impact-sync")
> +		test_impact(fd);
> +
> +	igt_exit();
> +
> +	return 0;
> +}
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-04-23 16:38 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
  2014-04-23 16:38   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
  2014-04-23 16:38   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
@ 2014-04-23 17:24   ` Volkin, Bradley D
  2 siblings, 0 replies; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-23 17:24 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

Reviewed-by: Brad Volkin <bradley.d.volkin@intel.com>

On Wed, Apr 23, 2014 at 05:38:33PM +0100, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> A set of userptr test cases to support the new feature.
> 
> For the eviction and swapping stress testing I have extracted
> some common behaviour from gem_evict_everything and made both
> test cases use it to avoid duplicating the code.
> 
> Both unsynchronized and synchronized userptr objects are
> tested but the latter set of tests will be skipped if kernel
> is compiled without MMU_NOTIFIERS.
> 
> Also, with 32-bit userspace swapping tests are skipped if
> the system has a lot more RAM than process address space.
> Forking swapping tests are not skipped since they can still
> trigger swapping by cumulative effect.
> 
> v2:
>    * Fixed dmabuf test.
>    * Added test for rejecting read-only.
>    * Fixed ioctl detection for latest kernel patch.
> 
> v3:
>    * Use ALIGN macro.
>    * Catchup with big lib/ reorganization.
>    * Fixed up some warnings.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>  tests/.gitignore          |    1 +
>  tests/Makefile.sources    |    1 +
>  tests/gem_userptr_blits.c | 1247 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1249 insertions(+)
>  create mode 100644 tests/gem_userptr_blits.c
> 
> diff --git a/tests/.gitignore b/tests/.gitignore
> index 146bab0..ff193bd 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -95,6 +95,7 @@ gem_tiling_max_stride
>  gem_unfence_active_buffers
>  gem_unref_active_buffers
>  gem_vmap_blits
> +gem_userptr_blits
>  gem_wait_render_timeout
>  gem_write_read_ring_switch
>  gen3_mixed_blits
> diff --git a/tests/Makefile.sources b/tests/Makefile.sources
> index c957ace..09d6aa3 100644
> --- a/tests/Makefile.sources
> +++ b/tests/Makefile.sources
> @@ -121,6 +121,7 @@ TESTS_progs = \
>  	gem_unfence_active_buffers \
>  	gem_unref_active_buffers \
>  	gem_vmap_blits \
> +	gem_userptr_blits \
>  	gem_wait_render_timeout \
>  	gen3_mixed_blits \
>  	gen3_render_linear_blits \
> diff --git a/tests/gem_userptr_blits.c b/tests/gem_userptr_blits.c
> new file mode 100644
> index 0000000..03af58e
> --- /dev/null
> +++ b/tests/gem_userptr_blits.c
> @@ -0,0 +1,1247 @@
> +/*
> + * Copyright © 2009-2014 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Eric Anholt <eric@anholt.net>
> + *    Chris Wilson <chris@chris-wilson.co.uk>
> + *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> + *
> + */
> +
> +/** @file gem_userptr_blits.c
> + *
> + * This is a test of doing many blits using a mixture of normal system pages
> + * and uncached linear buffers, with a working set larger than the
> + * aperture size.
> + *
> + * The goal is to simply ensure the basics work.
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <assert.h>
> +#include <sys/stat.h>
> +#include <sys/time.h>
> +#include <sys/mman.h>
> +#include "drm.h"
> +#include "i915_drm.h"
> +#include "drmtest.h"
> +#include "intel_bufmgr.h"
> +#include "intel_batchbuffer.h"
> +#include "intel_chipset.h"
> +#include "ioctl_wrappers.h"
> +
> +#include "eviction_common.c"
> +
> +#ifndef PAGE_SIZE
> +#define PAGE_SIZE 4096
> +#endif
> +
> +#define LOCAL_I915_GEM_USERPTR       0x34
> +#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
> +struct local_i915_gem_userptr {
> +	uint64_t user_ptr;
> +	uint64_t user_size;
> +	uint32_t flags;
> +#define LOCAL_I915_USERPTR_READ_ONLY (1<<0)
> +#define LOCAL_I915_USERPTR_UNSYNCHRONIZED (1<<31)
> +	uint32_t handle;
> +};
> +
> +static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
> +
> +#define WIDTH 512
> +#define HEIGHT 512
> +
> +static uint32_t linear[WIDTH*HEIGHT];
> +
> +static void gem_userptr_test_unsynchronized(void)
> +{
> +	userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
> +}
> +
> +static void gem_userptr_test_synchronized(void)
> +{
> +	userptr_flags = 0;
> +}
> +
> +static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
> +{
> +	struct local_i915_gem_userptr userptr;
> +	int ret;
> +
> +	userptr.user_ptr = (uintptr_t)ptr;
> +	userptr.user_size = size;
> +	userptr.flags = userptr_flags;
> +	if (read_only)
> +		userptr.flags |= LOCAL_I915_USERPTR_READ_ONLY;
> +
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	if (ret)
> +		ret = errno;
> +	igt_skip_on_f(ret == ENODEV &&
> +		      (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) == 0 &&
> +		      !read_only,
> +		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
> +	if (ret == 0)
> +		*handle = userptr.handle;
> +
> +	return ret;
> +}
> +
> +
> +static void gem_userptr_sync(int fd, uint32_t handle)
> +{
> +	gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
> +}
> +
> +static void
> +copy(int fd, uint32_t dst, uint32_t src, unsigned int error)
> +{
> +	uint32_t batch[12];
> +	struct drm_i915_gem_relocation_entry reloc[2];
> +	struct drm_i915_gem_exec_object2 obj[3];
> +	struct drm_i915_gem_execbuffer2 exec;
> +	uint32_t handle;
> +	int ret, i=0;
> +
> +	batch[i++] = XY_SRC_COPY_BLT_CMD |
> +		  XY_SRC_COPY_BLT_WRITE_ALPHA |
> +		  XY_SRC_COPY_BLT_WRITE_RGB;
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i - 1] |= 8;
> +	else
> +		batch[i - 1] |= 6;
> +
> +	batch[i++] = (3 << 24) | /* 32 bits */
> +		  (0xcc << 16) | /* copy ROP */
> +		  WIDTH*4;
> +	batch[i++] = 0; /* dst x1,y1 */
> +	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
> +	batch[i++] = 0; /* dst reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = 0; /* src x1,y1 */
> +	batch[i++] = WIDTH*4;
> +	batch[i++] = 0; /* src reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = MI_BATCH_BUFFER_END;
> +	batch[i++] = MI_NOOP;
> +
> +	handle = gem_create(fd, 4096);
> +	gem_write(fd, handle, 0, batch, sizeof(batch));
> +
> +	reloc[0].target_handle = dst;
> +	reloc[0].delta = 0;
> +	reloc[0].offset = 4 * sizeof(batch[0]);
> +	reloc[0].presumed_offset = 0;
> +	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
> +	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
> +
> +	reloc[1].target_handle = src;
> +	reloc[1].delta = 0;
> +	reloc[1].offset = 7 * sizeof(batch[0]);
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		reloc[1].offset += sizeof(batch[0]);
> +	reloc[1].presumed_offset = 0;
> +	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
> +	reloc[1].write_domain = 0;
> +
> +	obj[0].handle = dst;
> +	obj[0].relocation_count = 0;
> +	obj[0].relocs_ptr = 0;
> +	obj[0].alignment = 0;
> +	obj[0].offset = 0;
> +	obj[0].flags = 0;
> +	obj[0].rsvd1 = 0;
> +	obj[0].rsvd2 = 0;
> +
> +	obj[1].handle = src;
> +	obj[1].relocation_count = 0;
> +	obj[1].relocs_ptr = 0;
> +	obj[1].alignment = 0;
> +	obj[1].offset = 0;
> +	obj[1].flags = 0;
> +	obj[1].rsvd1 = 0;
> +	obj[1].rsvd2 = 0;
> +
> +	obj[2].handle = handle;
> +	obj[2].relocation_count = 2;
> +	obj[2].relocs_ptr = (uintptr_t)reloc;
> +	obj[2].alignment = 0;
> +	obj[2].offset = 0;
> +	obj[2].flags = 0;
> +	obj[2].rsvd1 = obj[2].rsvd2 = 0;
> +
> +	exec.buffers_ptr = (uintptr_t)obj;
> +	exec.buffer_count = 3;
> +	exec.batch_start_offset = 0;
> +	exec.batch_len = i * 4;
> +	exec.DR1 = exec.DR4 = 0;
> +	exec.num_cliprects = 0;
> +	exec.cliprects_ptr = 0;
> +	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
> +	i915_execbuffer2_set_context_id(exec, 0);
> +	exec.rsvd2 = 0;
> +
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> +	if (ret)
> +		ret = errno;
> +
> +	if (error == ~0)
> +		igt_assert(ret != 0);
> +	else
> +		igt_assert(ret == error);
> +
> +	gem_close(fd, handle);
> +}
> +
> +static void
> +blit(int fd, uint32_t dst, uint32_t src, uint32_t *all_bo, int n_bo, int error)
> +{
> +	uint32_t batch[12];
> +	struct drm_i915_gem_relocation_entry reloc[2];
> +	struct drm_i915_gem_exec_object2 *obj;
> +	struct drm_i915_gem_execbuffer2 exec;
> +	uint32_t handle;
> +	int n, ret, i=0;
> +
> +	batch[i++] = XY_SRC_COPY_BLT_CMD |
> +		  XY_SRC_COPY_BLT_WRITE_ALPHA |
> +		  XY_SRC_COPY_BLT_WRITE_RGB;
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i - 1] |= 8;
> +	else
> +		batch[i - 1] |= 6;
> +	batch[i++] = (3 << 24) | /* 32 bits */
> +		  (0xcc << 16) | /* copy ROP */
> +		  WIDTH*4;
> +	batch[i++] = 0; /* dst x1,y1 */
> +	batch[i++] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
> +	batch[i++] = 0; /* dst reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = 0; /* src x1,y1 */
> +	batch[i++] = WIDTH*4;
> +	batch[i++] = 0; /* src reloc */
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		batch[i++] = 0;
> +	batch[i++] = MI_BATCH_BUFFER_END;
> +	batch[i++] = MI_NOOP;
> +
> +	handle = gem_create(fd, 4096);
> +	gem_write(fd, handle, 0, batch, sizeof(batch));
> +
> +	reloc[0].target_handle = dst;
> +	reloc[0].delta = 0;
> +	reloc[0].offset = 4 * sizeof(batch[0]);
> +	reloc[0].presumed_offset = 0;
> +	reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;
> +	reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
> +
> +	reloc[1].target_handle = src;
> +	reloc[1].delta = 0;
> +	reloc[1].offset = 7 * sizeof(batch[0]);
> +	if (intel_gen(intel_get_drm_devid(fd)) >= 8)
> +		reloc[1].offset += sizeof(batch[0]);
> +	reloc[1].presumed_offset = 0;
> +	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
> +	reloc[1].write_domain = 0;
> +
> +	obj = calloc(n_bo + 1, sizeof(*obj));
> +	for (n = 0; n < n_bo; n++)
> +		obj[n].handle = all_bo[n];
> +	obj[n].handle = handle;
> +	obj[n].relocation_count = 2;
> +	obj[n].relocs_ptr = (uintptr_t)reloc;
> +
> +	exec.buffers_ptr = (uintptr_t)obj;
> +	exec.buffer_count = n_bo + 1;
> +	exec.batch_start_offset = 0;
> +	exec.batch_len = i * 4;
> +	exec.DR1 = exec.DR4 = 0;
> +	exec.num_cliprects = 0;
> +	exec.cliprects_ptr = 0;
> +	exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
> +	i915_execbuffer2_set_context_id(exec, 0);
> +	exec.rsvd2 = 0;
> +
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
> +	if (ret)
> +		ret = errno;
> +
> +	igt_assert(ret == error);
> +
> +	gem_close(fd, handle);
> +	free(obj);
> +}
> +
> +static uint32_t
> +create_userptr(int fd, uint32_t val, uint32_t *ptr)
> +{
> +	uint32_t handle;
> +	int i, ret;
> +
> +	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle);
> +	igt_assert(ret == 0);
> +	igt_assert(handle != 0);
> +
> +	/* Fill the BO with dwords starting at val */
> +	for (i = 0; i < WIDTH*HEIGHT; i++)
> +		ptr[i] = val++;
> +
> +	return handle;
> +}
> +
> +static void **handle_ptr_map;
> +static unsigned int num_handle_ptr_map;
> +
> +static void add_handle_ptr(uint32_t handle, void *ptr)
> +{
> +	if (handle >= num_handle_ptr_map) {
> +		handle_ptr_map = realloc(handle_ptr_map,
> +					 (handle + 1000) * sizeof(void*));
> +		num_handle_ptr_map = handle + 1000;
> +	}
> +
> +	handle_ptr_map[handle] = ptr;
> +}
> +
> +static void *get_handle_ptr(uint32_t handle)
> +{
> +	return handle_ptr_map[handle];
> +}
> +
> +static void free_handle_ptr(uint32_t handle)
> +{
> +	igt_assert(handle < num_handle_ptr_map);
> +	igt_assert(handle_ptr_map[handle]);
> +
> +	free(handle_ptr_map[handle]);
> +	handle_ptr_map[handle] = NULL;
> +}
> +
> +static uint32_t create_userptr_bo(int fd, int size)
> +{
> +	void *ptr;
> +	uint32_t handle;
> +	int ret;
> +
> +	ret = posix_memalign(&ptr, PAGE_SIZE, size);
> +	igt_assert(ret == 0);
> +
> +	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
> +	igt_assert(ret == 0);
> +	add_handle_ptr(handle, ptr);
> +
> +	return handle;
> +}
> +
> +static void clear(int fd, uint32_t handle, int size)
> +{
> +	void *ptr = get_handle_ptr(handle);
> +
> +	igt_assert(ptr != NULL);
> +
> +	memset(ptr, 0, size);
> +}
> +
> +static void free_userptr_bo(int fd, uint32_t handle)
> +{
> +	gem_close(fd, handle);
> +	free_handle_ptr(handle);
> +}
> +
> +static uint32_t
> +create_bo(int fd, uint32_t val)
> +{
> +	uint32_t handle;
> +	int i;
> +
> +	handle = gem_create(fd, sizeof(linear));
> +
> +	/* Fill the BO with dwords starting at val */
> +	for (i = 0; i < WIDTH*HEIGHT; i++)
> +		linear[i] = val++;
> +	gem_write(fd, handle, 0, linear, sizeof(linear));
> +
> +	return handle;
> +}
> +
> +static void
> +check_cpu(uint32_t *ptr, uint32_t val)
> +{
> +	int i;
> +
> +	for (i = 0; i < WIDTH*HEIGHT; i++) {
> +		if (ptr[i] != val) {
> +			fprintf(stderr, "Expected 0x%08x, found 0x%08x "
> +				"at offset 0x%08x\n",
> +				val, ptr[i], i * 4);
> +			abort();
> +		}
> +		val++;
> +	}
> +}
> +
> +static void
> +check_gpu(int fd, uint32_t handle, uint32_t val)
> +{
> +	gem_read(fd, handle, 0, linear, sizeof(linear));
> +	check_cpu(linear, val);
> +}
> +
> +static int has_userptr(int fd)
> +{
> +	uint32_t handle = 0;
> +	void *ptr;
> +	uint32_t oldflags;
> +	int ret;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +	oldflags = userptr_flags;
> +	gem_userptr_test_unsynchronized();
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	userptr_flags = oldflags;
> +	if (ret != 0) {
> +		free(ptr);
> +		return 0;
> +	}
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return handle != 0;
> +}
> +
> +static int test_input_checking(int fd)
> +{
> +	struct local_i915_gem_userptr userptr;
> +	int ret;
> +
> +	/* Invalid flags. */
> +	userptr.user_ptr = 0;
> +	userptr.user_size = 0;
> +	userptr.flags = ~0;
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	igt_assert(ret != 0);
> +
> +	/* Too big. */
> +	userptr.user_ptr = 0;
> +	userptr.user_size = ~0;
> +	userptr.flags = 0;
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	igt_assert(ret != 0);
> +
> +	/* Both wrong. */
> +	userptr.user_ptr = 0;
> +	userptr.user_size = ~0;
> +	userptr.flags = ~0;
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	igt_assert(ret != 0);
> +
> +	return 0;
> +}
> +
> +static int test_access_control(int fd)
> +{
> +	igt_fork(child, 1) {
> +		void *ptr;
> +		int ret;
> +		uint32_t handle;
> +
> +		igt_drop_root();
> +
> +		/* CAP_SYS_ADMIN is needed for UNSYNCHRONIZED mappings. */
> +		gem_userptr_test_unsynchronized();
> +
> +		igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +
> +		ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +		if (ret == 0)
> +			gem_close(fd, handle);
> +		free(ptr);
> +		igt_assert(ret == EPERM);
> +	}
> +
> +	igt_waitchildren();
> +
> +	return 0;
> +}
> +
> +static int test_invalid_mapping(int fd)
> +{
> +	int ret;
> +	uint32_t handle, handle2;
> +	void *ptr;
> +
> +	/* NULL pointer. */
> +	ret = gem_userptr(fd, NULL, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
> +	gem_close(fd, handle);
> +
> +	/* GTT mapping */
> +	handle = create_bo(fd, 0);
> +	ptr = gem_mmap__gtt(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
> +	if (ptr == NULL)
> +		gem_close(fd, handle);
> +	assert(ptr != NULL);
> +	assert(((unsigned long)ptr & (PAGE_SIZE - 1)) == 0);
> +	assert((sizeof(linear) & (PAGE_SIZE - 1)) == 0);
> +	ret = gem_userptr(fd, ptr, sizeof(linear), 0, &handle2);
> +	igt_assert(ret == 0);
> +	copy(fd, handle, handle, ~0); /* QQQ Precise errno? */
> +	gem_close(fd, handle2);
> +	munmap(ptr, sizeof(linear));
> +	gem_close(fd, handle);
> +
> +	return 0;
> +}
> +
> +static int test_forbidden_ops(int fd)
> +{
> +	void *ptr;
> +	int ret;
> +	uint32_t handle;
> +	char buf[PAGE_SIZE];
> +	struct drm_i915_gem_pread gem_pread;
> +	struct drm_i915_gem_pwrite gem_pwrite;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +
> +	gem_pread.handle = handle;
> +	gem_pread.offset = 0;
> +	gem_pread.size = PAGE_SIZE;
> +	gem_pread.data_ptr = (uintptr_t)buf;
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PREAD, &gem_pread);
> +	if (ret == 0) {
> +		gem_close(fd, handle);
> +		free(ptr);
> +	}
> +	igt_assert(ret != 0);
> +
> +	gem_pwrite.handle = handle;
> +	gem_pwrite.offset = 0;
> +	gem_pwrite.size = PAGE_SIZE;
> +	gem_pwrite.data_ptr = (uintptr_t)buf;
> +	ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &gem_pwrite);
> +	if (ret == 0) {
> +		gem_close(fd, handle);
> +		free(ptr);
> +	}
> +	igt_assert(ret != 0);
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static char counter;
> +
> +static void (*orig_sigbus)(int sig, siginfo_t *info, void *param);
> +static unsigned long sigbus_start;
> +static long sigbus_cnt = -1;
> +
> +static void
> +check_bo(int fd1, uint32_t handle1, int is_userptr, int fd2, uint32_t handle2)
> +{
> +	char *ptr1, *ptr2;
> +	int i;
> +	unsigned long size = sizeof(linear);
> +
> +	if (is_userptr)
> +		ptr1 = get_handle_ptr(handle1);
> +	else
> +		ptr1 = gem_mmap(fd1, handle1, sizeof(linear), PROT_READ | PROT_WRITE);
> +
> +	ptr2 = gem_mmap(fd2, handle2, sizeof(linear), PROT_READ | PROT_WRITE);
> +
> +	igt_assert(ptr1);
> +	igt_assert(ptr2);
> +
> +	sigbus_start = (unsigned long)ptr2;
> +
> +	if (sigbus_cnt == 0)
> +		size = 1;
> +
> +	/* check whether it's still our old object first. */
> +	for (i = 0; i < size; i++) {
> +		igt_assert(ptr1[i] == counter);
> +		igt_assert(ptr2[i] == counter);
> +	}
> +
> +	counter++;
> +
> +	if (size > 1) {
> +		memset(ptr1, counter, size);
> +		igt_assert(memcmp(ptr1, ptr2, size) == 0);
> +	}
> +
> +	if (!is_userptr)
> +		munmap(ptr1, sizeof(linear));
> +	munmap(ptr2, sizeof(linear));
> +}
> +
> +static int export_handle(int fd, uint32_t handle, int *outfd)
> +{
> +	struct drm_prime_handle args;
> +	int ret;
> +
> +	args.handle = handle;
> +	args.flags = DRM_CLOEXEC;
> +	args.fd = -1;
> +
> +	ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
> +	if (ret)
> +		ret = errno;
> +	*outfd = args.fd;
> +
> +	return ret;
> +}
> +
> +static void sigbus(int sig, siginfo_t *info, void *param)
> +{
> +	unsigned long ptr = (unsigned long)info->si_addr;
> +	void *addr;
> +
> +	if (ptr >= sigbus_start &&
> +	    ptr <= (sigbus_start + sizeof(linear))) {
> +		sigbus_cnt++;
> +		addr = mmap((void *)ptr, sizeof(linear), PROT_READ | PROT_WRITE,
> +				MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
> +		if ((unsigned long)addr == ptr) {
> +			memset(addr, counter, sizeof(linear));
> +			return;
> +		}
> +	}
> +
> +	if (orig_sigbus)
> +		orig_sigbus(sig, info, param);
> +	assert(0);
> +}
> +
> +static int test_dmabuf(void)
> +{
> +	int fd1, fd2;
> +	uint32_t handle, handle_import1, handle_import2, handle_selfimport;
> +	int dma_buf_fd = -1;
> +	int ret;
> +	struct sigaction sigact, orig_sigact;
> +
> +	fd1 = drm_open_any();
> +	fd2 = drm_open_any();
> +
> +	handle = create_userptr_bo(fd1, sizeof(linear));
> +
> +	ret = export_handle(fd1, handle, &dma_buf_fd);
> +	if (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) {
> +		igt_assert(ret == EINVAL);
> +		free_userptr_bo(fd1, handle);
> +
> +		return 0;
> +	} else {
> +		igt_assert(ret == 0);
> +		igt_assert(dma_buf_fd >= 0);
> +	}
> +	handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd);
> +	check_bo(fd1, handle, 1, fd2, handle_import1);
> +
> +	/* reimport should give us the same handle so that userspace can check
> +	 * whether it has that bo already somewhere. */
> +	handle_import2 = prime_fd_to_handle(fd2, dma_buf_fd);
> +	igt_assert(handle_import1 == handle_import2);
> +
> +	/* Same for re-importing on the exporting fd. */
> +	handle_selfimport = prime_fd_to_handle(fd1, dma_buf_fd);
> +	igt_assert(handle == handle_selfimport);
> +
> +	/* close dma_buf, check whether nothing disappears. */
> +	close(dma_buf_fd);
> +	check_bo(fd1, handle, 1, fd2, handle_import1);
> +
> +	/* destroy userptr object and expect SIGBUS */
> +	free_userptr_bo(fd1, handle);
> +	sigact.sa_sigaction = sigbus;
> +	sigact.sa_flags = SA_SIGINFO;
> +	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
> +	assert(ret == 0);
> +	orig_sigbus = orig_sigact.sa_sigaction;
> +	sigbus_cnt = 0;
> +	check_bo(fd2, handle_import1, 0, fd2, handle_import1);
> +	assert(sigbus_cnt > 0);
> +	sigact.sa_sigaction = orig_sigbus;
> +	sigact.sa_flags = SA_SIGINFO;
> +	ret = sigaction(SIGBUS, &sigact, &orig_sigact);
> +	assert(ret == 0);
> +
> +	gem_close(fd2, handle_import1);
> +	close(fd1);
> +	close(fd2);
> +
> +	return 0;
> +}
> +
> +static int test_usage_restrictions(int fd)
> +{
> +	void *ptr;
> +	int ret;
> +	uint32_t handle;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE * 2) == 0);
> +
> +	/* Address not aligned. */
> +	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret != 0);
> +
> +	/* Size not rounded to page size. */
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE - 1, 0, &handle);
> +	igt_assert(ret != 0);
> +
> +	/* Both wrong. */
> +	ret = gem_userptr(fd, (char *)ptr + 1, PAGE_SIZE - 1, 0, &handle);
> +	igt_assert(ret != 0);
> +
> +	/* Read-only not supported. */
> +	ret = gem_userptr(fd, (char *)ptr, PAGE_SIZE, 1, &handle);
> +	igt_assert(ret != 0);
> +
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static int test_create_destroy(int fd)
> +{
> +	void *ptr;
> +	int ret;
> +	uint32_t handle;
> +
> +	igt_assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static int test_coherency(int fd, int count)
> +{
> +	uint32_t *memory;
> +	uint32_t *cpu, *cpu_val;
> +	uint32_t *gpu, *gpu_val;
> +	uint32_t start = 0;
> +	int i, ret;
> +
> +	printf("Using 2x%d 1MiB buffers\n", count);
> +
> +	ret = posix_memalign((void **)&memory, PAGE_SIZE, count*sizeof(linear));
> +	if (ret != 0 || memory == NULL) {
> +		fprintf(stderr, "Unable to allocate %lld bytes\n",
> +			(long long)count*sizeof(linear));
> +		return 1;
> +	}
> +
> +	gpu = malloc(sizeof(uint32_t)*count*4);
> +	gpu_val = gpu + count;
> +	cpu = gpu_val + count;
> +	cpu_val = cpu + count;
> +
> +	for (i = 0; i < count; i++) {
> +		gpu[i] = create_bo(fd, start);
> +		gpu_val[i] = start;
> +		start += WIDTH*HEIGHT;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		cpu[i] = create_userptr(fd, start, memory+i*WIDTH*HEIGHT);
> +		cpu_val[i] = start;
> +		start += WIDTH*HEIGHT;
> +	}
> +
> +	printf("Verifying initialisation...\n");
> +	for (i = 0; i < count; i++) {
> +		check_gpu(fd, gpu[i], gpu_val[i]);
> +		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> +	}
> +
> +	printf("Cyclic blits cpu->gpu, forward...\n");
> +	for (i = 0; i < count * 4; i++) {
> +		int src = i % count;
> +		int dst = (i + 1) % count;
> +
> +		copy(fd, gpu[dst], cpu[src], 0);
> +		gpu_val[dst] = cpu_val[src];
> +	}
> +	for (i = 0; i < count; i++)
> +		check_gpu(fd, gpu[i], gpu_val[i]);
> +
> +	printf("Cyclic blits gpu->cpu, backward...\n");
> +	for (i = 0; i < count * 4; i++) {
> +		int src = (i + 1) % count;
> +		int dst = i % count;
> +
> +		copy(fd, cpu[dst], gpu[src], 0);
> +		cpu_val[dst] = gpu_val[src];
> +	}
> +	for (i = 0; i < count; i++) {
> +		gem_userptr_sync(fd, cpu[i]);
> +		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> +	}
> +
> +	printf("Random blits...\n");
> +	for (i = 0; i < count * 4; i++) {
> +		int src = random() % count;
> +		int dst = random() % count;
> +
> +		if (random() & 1) {
> +			copy(fd, gpu[dst], cpu[src], 0);
> +			gpu_val[dst] = cpu_val[src];
> +		} else {
> +			copy(fd, cpu[dst], gpu[src], 0);
> +			cpu_val[dst] = gpu_val[src];
> +		}
> +	}
> +	for (i = 0; i < count; i++) {
> +		check_gpu(fd, gpu[i], gpu_val[i]);
> +		gem_close(fd, gpu[i]);
> +
> +		gem_userptr_sync(fd, cpu[i]);
> +		check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
> +		gem_close(fd, cpu[i]);
> +	}
> +
> +	free(gpu);
> +	free(memory);
> +
> +	return 0;
> +}
> +
> +static struct igt_eviction_test_ops fault_ops = {
> +	.create = create_userptr_bo,
> +	.close = free_userptr_bo,
> +	.copy = blit,
> +	.clear = clear,
> +};
> +
> +static int can_swap(void)
> +{
> +	unsigned long as, ram;
> +
> +	/* Cannot swap if not enough address space */
> +
> +	/* FIXME: Improve check criteria. */
> +	if (sizeof(void*) < 8)
> +		as = 3 * 1024;
> +	else
> +		as = 256 * 1024; /* Just a big number */
> +
> +	ram = intel_get_total_ram_mb();
> +
> +	if ((as - 128) < (ram - 256))
> +		return 0;
> +
> +	return 1;
> +}
> +
> +#define min(a, b) ((a) < (b) ? (a) : (b))
> +
> +static void test_forking_evictions(int fd, int size, int count,
> +			     unsigned flags)
> +{
> +	int trash_count;
> +	int num_threads;
> +
> +	trash_count = intel_get_total_ram_mb() * 11 / 10;
> +	/* Use the fact test will spawn a number of child
> +	 * processes meaning swapping will be triggered system
> +	 * wide even if one process on it's own can't do it.
> +	 */
> +	num_threads = min(sysconf(_SC_NPROCESSORS_ONLN) * 4, 12);
> +	trash_count /= num_threads;
> +	if (count > trash_count)
> +		count = trash_count;
> +
> +	forking_evictions(fd, &fault_ops, size, count, trash_count, flags);
> +}
> +
> +static void test_swapping_evictions(int fd, int size, int count)
> +{
> +	int trash_count;
> +
> +	igt_skip_on_f(!can_swap(),
> +		"Not enough process address space for swapping tests.\n");
> +
> +	trash_count = intel_get_total_ram_mb() * 11 / 10;
> +
> +	swapping_evictions(fd, &fault_ops, size, count, trash_count);
> +}
> +
> +static void test_minor_evictions(int fd, int size, int count)
> +{
> +	minor_evictions(fd, &fault_ops, size, count);
> +}
> +
> +static void test_major_evictions(int fd, int size, int count)
> +{
> +	major_evictions(fd, &fault_ops, size, count);
> +}
> +
> +static int test_overlap(int fd, int expected)
> +{
> +	char *ptr;
> +	int ret;
> +	uint32_t handle, handle2;
> +
> +	igt_assert(posix_memalign((void *)&ptr, PAGE_SIZE, PAGE_SIZE * 3) == 0);
> +
> +	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE, 0, &handle);
> +	igt_assert(ret == 0);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle2);
> +	igt_assert(ret == 0);
> +	gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr + PAGE_SIZE * 2, PAGE_SIZE, 0, &handle2);
> +	igt_assert(ret == 0);
> +	gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE * 2, 0, &handle2);
> +	igt_assert(ret == expected);
> +	if (ret == 0)
> +		gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr + PAGE_SIZE, PAGE_SIZE * 2, 0, &handle2);
> +	igt_assert(ret == expected);
> +	if (ret == 0)
> +		gem_close(fd, handle2);
> +
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE * 3, 0, &handle2);
> +	igt_assert(ret == expected);
> +	if (ret == 0)
> +		gem_close(fd, handle2);
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return 0;
> +}
> +
> +static int test_unmap(int fd, int expected)
> +{
> +	char *ptr, *bo_ptr;
> +	const unsigned int num_obj = 3;
> +	unsigned int i;
> +	uint32_t bo[num_obj + 1];
> +	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
> +	int ret;
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
> +
> +	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
> +		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
> +		igt_assert(ret == 0);
> +	}
> +
> +	bo[num_obj] = create_bo(fd, 0);
> +
> +	for (i = 0; i < num_obj; i++)
> +		copy(fd, bo[num_obj], bo[i], 0);
> +
> +	ret = munmap(ptr, map_size);
> +	assert(ret == 0);
> +
> +	for (i = 0; i < num_obj; i++)
> +		copy(fd, bo[num_obj], bo[i], expected);
> +
> +	for (i = 0; i < (num_obj + 1); i++)
> +		gem_close(fd, bo[i]);
> +
> +	return 0;
> +}
> +
> +static int test_unmap_after_close(int fd)
> +{
> +	char *ptr, *bo_ptr;
> +	const unsigned int num_obj = 3;
> +	unsigned int i;
> +	uint32_t bo[num_obj + 1];
> +	size_t map_size = sizeof(linear) * num_obj + (PAGE_SIZE - 1);
> +	int ret;
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +				MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
> +
> +	for (i = 0; i < num_obj; i++, bo_ptr += sizeof(linear)) {
> +		ret = gem_userptr(fd, bo_ptr, sizeof(linear), 0, &bo[i]);
> +		igt_assert(ret == 0);
> +	}
> +
> +	bo[num_obj] = create_bo(fd, 0);
> +
> +	for (i = 0; i < num_obj; i++)
> +		copy(fd, bo[num_obj], bo[i], 0);
> +
> +	for (i = 0; i < (num_obj + 1); i++)
> +		gem_close(fd, bo[i]);
> +
> +	ret = munmap(ptr, map_size);
> +	assert(ret == 0);
> +
> +	return 0;
> +}
> +
> +static int test_unmap_cycles(int fd, int expected)
> +{
> +	int i;
> +
> +	for (i = 0; i < 1000; i++)
> +		test_unmap(fd, expected);
> +
> +	return 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	uint64_t aperture_size;
> +	unsigned int total_ram;
> +	int fd = -1, count = 0, size = 0, ret;
> +
> +	igt_skip_on_simulation();
> +
> +	igt_subtest_init(argc, argv);
> +
> +	igt_fixture {
> +		fd = drm_open_any();
> +		igt_assert(fd >= 0);
> +
> +		ret = has_userptr(fd);
> +		igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
> +			      strerror(errno), ret);
> +
> +		size = sizeof(linear);
> +
> +		aperture_size = gem_aperture_size(fd);
> +		printf("Aperture size is %lu MiB\n", (long)(aperture_size / (1024*1024)));
> +
> +		if (argc > 1)
> +			count = atoi(argv[1]);
> +		if (count == 0)
> +			count = 2 * aperture_size / (1024*1024) / 3;
> +
> +		total_ram = intel_get_total_ram_mb();
> +		printf("Total RAM is %u MiB\n", total_ram);
> +
> +		if (count > total_ram * 3 / 4) {
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +			printf("Not enough RAM to run test, reducing buffer count.\n");
> +		}
> +	}
> +
> +	igt_subtest("input-checking")
> +		test_input_checking(fd);
> +
> +	igt_subtest("usage-restrictions")
> +		test_usage_restrictions(fd);
> +
> +	igt_subtest("invalid-mapping")
> +		test_invalid_mapping(fd);
> +
> +	igt_subtest("forbidden-operations")
> +		test_forbidden_ops(fd);
> +
> +	printf("Testing unsynchronized mappings...\n");
> +	gem_userptr_test_unsynchronized();
> +
> +	igt_subtest("create-destroy-unsync")
> +		test_create_destroy(fd);
> +
> +	igt_subtest("unsync-overlap")
> +		test_overlap(fd, 0);
> +
> +	igt_subtest("unsync-unmap")
> +		test_unmap(fd, 0);
> +
> +	igt_subtest("unsync-unmap-cycles")
> +		test_unmap_cycles(fd, 0);
> +
> +	igt_subtest("unsync-unmap-after-close")
> +		test_unmap_after_close(fd);
> +
> +	igt_subtest("coherency-unsync")
> +		test_coherency(fd, count);
> +
> +	igt_subtest("dmabuf-unsync")
> +		test_dmabuf();
> +
> +	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
> +		igt_subtest_f("forked-unsync%s%s%s-%s",
> +		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
> +		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
> +		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
> +				"-mempressure" : "",
> +		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
> +				"interruptible" : "normal") {
> +			test_forking_evictions(fd, size, count, flags);
> +		}
> +	}
> +
> +	igt_subtest("swapping-unsync-normal")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-unsync-normal")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-unsync-normal") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_fixture {
> +		size = sizeof(linear);
> +		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
> +		if (count > total_ram * 3 / 4)
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +	}
> +
> +	igt_fork_signal_helper();
> +
> +	igt_subtest("swapping-unsync-interruptible")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-unsync-interruptible")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-unsync-interruptible") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_stop_signal_helper();
> +
> +	printf("Testing synchronized mappings...\n");
> +
> +	igt_fixture {
> +		size = sizeof(linear);
> +		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
> +		if (count > total_ram * 3 / 4)
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +	}
> +
> +	gem_userptr_test_synchronized();
> +
> +	igt_subtest("create-destroy-sync")
> +		test_create_destroy(fd);
> +
> +	igt_subtest("sync-overlap")
> +		test_overlap(fd, EINVAL);
> +
> +	igt_subtest("sync-unmap")
> +		test_unmap(fd, EFAULT);
> +
> +	igt_subtest("sync-unmap-cycles")
> +		test_unmap_cycles(fd, EFAULT);
> +
> +	igt_subtest("sync-unmap-after-close")
> +		test_unmap_after_close(fd);
> +
> +	igt_subtest("coherency-sync")
> +		test_coherency(fd, count);
> +
> +	igt_subtest("dmabuf-sync")
> +		test_dmabuf();
> +
> +	for (unsigned flags = 0; flags < ALL_FORKING_EVICTIONS + 1; flags++) {
> +		igt_subtest_f("forked-sync%s%s%s-%s",
> +		    flags & FORKING_EVICTIONS_SWAPPING ? "-swapping" : "",
> +		    flags & FORKING_EVICTIONS_DUP_DRMFD ? "-multifd" : "",
> +		    flags & FORKING_EVICTIONS_MEMORY_PRESSURE ?
> +				"-mempressure" : "",
> +		    flags & FORKING_EVICTIONS_INTERRUPTIBLE ?
> +				"interruptible" : "normal") {
> +			test_forking_evictions(fd, size, count, flags);
> +		}
> +	}
> +
> +	igt_subtest("swapping-normal-sync")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-normal-sync")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-normal-sync") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_fixture {
> +		size = 1024 * 1024;
> +		count = 2 * gem_aperture_size(fd) / (1024*1024) / 3;
> +		if (count > total_ram * 3 / 4)
> +			count = intel_get_total_ram_mb() * 3 / 4;
> +	}
> +
> +	igt_fork_signal_helper();
> +
> +	igt_subtest("swapping-sync-interruptible")
> +		test_swapping_evictions(fd, size, count);
> +
> +	igt_subtest("minor-sync-interruptible")
> +		test_minor_evictions(fd, size, count);
> +
> +	igt_subtest("major-sync-interruptible") {
> +		size = 200 * 1024 * 1024;
> +		count = (gem_aperture_size(fd) / size) + 2;
> +		test_major_evictions(fd, size, count);
> +	}
> +
> +	igt_stop_signal_helper();
> +
> +	igt_subtest("access-control")
> +	test_access_control(fd);
> +
> +	igt_exit();
> +
> +	return 0;
> +}
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases
  2014-04-23 15:32         ` Volkin, Bradley D
@ 2014-04-23 17:53           ` Daniel Vetter
  0 siblings, 0 replies; 28+ messages in thread
From: Daniel Vetter @ 2014-04-23 17:53 UTC (permalink / raw)
  To: Volkin, Bradley D; +Cc: Intel-gfx

On Wed, Apr 23, 2014 at 08:32:27AM -0700, Volkin, Bradley D wrote:
> On Wed, Apr 23, 2014 at 06:33:40AM -0700, Tvrtko Ursulin wrote:
> > 
> > On 04/18/2014 06:10 PM, Volkin, Bradley D wrote:
> > > On Wed, Mar 19, 2014 at 04:13:04AM -0700, Tvrtko Ursulin wrote:
> > >> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> > >>
> > >> A set of userptr test cases to support the new feature.
> > >>
> > >> For the eviction and swapping stress testing I have extracted
> > >> some common behaviour from gem_evict_everything and made both
> > >> test cases use it to avoid duplicating the code.
> > >>
> > >> Both unsynchronized and synchronized userptr objects are
> > >> tested but the latter set of tests will be skipped if kernel
> > >> is compiled without MMU_NOTIFIERS.
> > >>
> > >> Also, with 32-bit userspace swapping tests are skipped if
> > >> the system has a lot more RAM than process address space.
> > >> Forking swapping tests are not skipped since they can still
> > >> trigger swapping by cumulative effect.
> > >>
> > >> v2:
> > >>     * Fixed dmabuf test.
> > >>     * Added test for rejecting read-only.
> > >>     * Fixed ioctl detection for latest kernel patch.
> > >>
> > >> v3:
> > >>     * Updated copy() for Gen8+.
> > >>     * Fixed ioctl detection on kernels without MMU_NOTIFIERs.
> > >>
> > >> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> > >
> > > A number of the comments I made on patch 3 apply here as well.
> > > The sizeof(linear) thing is more prevalent in this test, though
> > > it looks like linear is at least used. Other than those comments
> > > this looks good to me.
> > 
> > Believe it or not that sizeof(linear) "idiom" I inherited from other 
> > blitter tests. Personally I don't care one way or another. But since it 
> > makes sense to get rid of it for the benchmark part, perhaps I should 
> > change it here as well to be consistent. How strongly do you feel 
> > strongly about this?
> 
> I think changing it would be slightly more readable, but if it's
> consistent with other blit tests then I don't feel too strongly
> about it. In fact, consistency with the other tests might be the
> better approach. I'm fine with whichever approach you prefer.

Some of the igt tests are so Gross Hacks that justifying ugliness in new
tests with consistency is ill-advised ;-)

If you find some spare cycles to clean up existing tests that would be
awesome, but I don't mind if they keep being ugly.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-02-26 16:17 [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
                   ` (4 preceding siblings ...)
  2014-04-23 16:38 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
@ 2014-04-24  9:07 ` Tvrtko Ursulin
  2014-04-24 16:07   ` Volkin, Bradley D
  5 siblings, 1 reply; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-04-24  9:07 UTC (permalink / raw)
  To: Intel-gfx

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This adds a small benchmark for the new userptr functionality.

Apart from basic surface creation and destruction, also tested is the
impact of having userptr surfaces in the process address space. Reason
for that is the impact of MMU notifiers on common address space
operations like munmap() which is per process.

v2:
  * Moved to benchmarks.
  * Added pointer read/write tests.
  * Changed output to say iterations per second instead of
    operations per second.
  * Multiply result by batch size for multi-create* tests
    for a more comparable number with create-destroy test.

v3:
  * Use ALIGN macro.
  * Catchup with big lib/ reorganization.
  * Removed unused code and one global variable.
  * Fixed up some warnings.

v4:
  * Fixed feature test, does not matter here but makes it
    consistent with gem_userptr_blits and clearer.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Brad Volkin <bradley.d.volkin@intel.com>
---
 benchmarks/.gitignore              |   1 +
 benchmarks/Makefile.sources        |   3 +-
 benchmarks/gem_userptr_benchmark.c | 498 +++++++++++++++++++++++++++++++++++++
 3 files changed, 501 insertions(+), 1 deletion(-)
 create mode 100644 benchmarks/gem_userptr_benchmark.c

diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
index ddea6f7..09e5bd8 100644
--- a/benchmarks/.gitignore
+++ b/benchmarks/.gitignore
@@ -1,3 +1,4 @@
+gem_userptr_benchmark
 intel_upload_blit_large
 intel_upload_blit_large_gtt
 intel_upload_blit_large_map
diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
index f9da579..60bdae2 100644
--- a/benchmarks/Makefile.sources
+++ b/benchmarks/Makefile.sources
@@ -2,4 +2,5 @@ bin_PROGRAMS =                          \
 	intel_upload_blit_large         \
 	intel_upload_blit_large_gtt     \
 	intel_upload_blit_large_map     \
-	intel_upload_blit_small
+	intel_upload_blit_small		\
+	gem_userptr_benchmark
diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
new file mode 100644
index 0000000..9ad6e4a
--- /dev/null
+++ b/benchmarks/gem_userptr_benchmark.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
+ *
+ */
+
+/** @file gem_userptr_benchmark.c
+ *
+ * Benchmark the userptr code and impact of having userptr surfaces
+ * in process address space on some normal operations.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_chipset.h"
+#include "ioctl_wrappers.h"
+#include "igt_aux.h"
+
+#ifndef PAGE_SIZE
+  #define PAGE_SIZE 4096
+#endif
+
+#define LOCAL_I915_GEM_USERPTR       0x34
+#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
+struct local_i915_gem_userptr {
+	uint64_t user_ptr;
+	uint64_t user_size;
+	uint32_t flags;
+#define LOCAL_I915_USERPTR_READ_ONLY (1<<0)
+#define LOCAL_I915_USERPTR_UNSYNCHRONIZED (1<<31)
+	uint32_t handle;
+};
+
+static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+
+#define BO_SIZE (65536)
+
+static void gem_userptr_test_unsynchronized(void)
+{
+	userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
+}
+
+static void gem_userptr_test_synchronized(void)
+{
+	userptr_flags = 0;
+}
+
+static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
+{
+	struct local_i915_gem_userptr userptr;
+	int ret;
+
+	userptr.user_ptr = (uintptr_t)ptr;
+	userptr.user_size = size;
+	userptr.flags = userptr_flags;
+	if (read_only)
+		userptr.flags |= LOCAL_I915_USERPTR_READ_ONLY;
+
+	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
+	if (ret)
+		ret = errno;
+	igt_skip_on_f(ret == ENODEV &&
+		      (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) == 0 &&
+		      !read_only,
+		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
+	if (ret == 0)
+		*handle = userptr.handle;
+
+	return ret;
+}
+
+static void **handle_ptr_map;
+static unsigned int num_handle_ptr_map;
+
+static void add_handle_ptr(uint32_t handle, void *ptr)
+{
+	if (handle >= num_handle_ptr_map) {
+		handle_ptr_map = realloc(handle_ptr_map,
+					 (handle + 1000) * sizeof(void*));
+		num_handle_ptr_map = handle + 1000;
+	}
+
+	handle_ptr_map[handle] = ptr;
+}
+
+static void *get_handle_ptr(uint32_t handle)
+{
+	return handle_ptr_map[handle];
+}
+
+static void free_handle_ptr(uint32_t handle)
+{
+	igt_assert(handle < num_handle_ptr_map);
+	igt_assert(handle_ptr_map[handle]);
+
+	free(handle_ptr_map[handle]);
+	handle_ptr_map[handle] = NULL;
+}
+
+static uint32_t create_userptr_bo(int fd, int size)
+{
+	void *ptr;
+	uint32_t handle;
+	int ret;
+
+	ret = posix_memalign(&ptr, PAGE_SIZE, size);
+	igt_assert(ret == 0);
+
+	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
+	igt_assert(ret == 0);
+	add_handle_ptr(handle, ptr);
+
+	return handle;
+}
+
+static void free_userptr_bo(int fd, uint32_t handle)
+{
+	gem_close(fd, handle);
+	free_handle_ptr(handle);
+}
+
+static int has_userptr(int fd)
+{
+	uint32_t handle = 0;
+	void *ptr;
+	uint32_t oldflags;
+	int ret;
+
+	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
+	oldflags = userptr_flags;
+	gem_userptr_test_unsynchronized();
+	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
+	userptr_flags = oldflags;
+	if (ret != 0) {
+		free(ptr);
+		return 0;
+	}
+
+	gem_close(fd, handle);
+	free(ptr);
+
+	return handle != 0;
+}
+
+static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
+static const unsigned int test_duration_sec = 3;
+
+static volatile unsigned int run_test;
+
+static void alarm_handler(int sig)
+{
+	assert(run_test == 1);
+	run_test = 0;
+}
+
+static void start_test(unsigned int duration)
+{
+	run_test = 1;
+	if (duration == 0)
+		duration = test_duration_sec;
+	signal(SIGALRM, alarm_handler);
+	alarm(duration);
+}
+
+static void exchange_ptr(void *array, unsigned i, unsigned j)
+{
+	void **arr, *tmp;
+	arr = (void **)array;
+
+	tmp = arr[i];
+	arr[i] = arr[j];
+	arr[j] = tmp;
+}
+
+static void test_malloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_malloc_realloc_free(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = malloc(1000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++) {
+			ptr[i] = realloc(ptr[i], 2000);
+			assert(ptr[i]);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			free(ptr[i]);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_mmap_unmap(int random)
+{
+	unsigned long iter = 0;
+	unsigned int i, tot = 1000;
+	void *ptr[tot];
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		for (i = 0; i < tot; i++) {
+			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
+					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+			assert(ptr[i] != MAP_FAILED);
+		}
+		if (random)
+			igt_permute_array(ptr, tot, exchange_ptr);
+		for (i = 0; i < tot; i++)
+			munmap(ptr[i], 1000);
+		iter++;
+	}
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_ptr_read(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	unsigned long i, loops;
+	register unsigned long v;
+
+	loops = BO_SIZE / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			v = *p++;
+			v = *p++;
+			v = *p++;
+			v = *p++;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
+}
+
+static void test_ptr_write(void *ptr)
+{
+	unsigned long iter = 0;
+	volatile unsigned long *p;
+	register unsigned long i, loops;
+
+	loops = BO_SIZE / sizeof(unsigned long) / 4;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		p = (unsigned long *)ptr;
+		for (i = 0; i < loops; i++) {
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+			*p++ = i;
+		}
+		iter++;
+	}
+
+	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
+}
+
+static void test_impact(int fd)
+{
+	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
+	unsigned int subtest, i;
+	uint32_t handles[nr_bos[total-1]];
+	void *ptr;
+	char buffer[BO_SIZE];
+
+	for (subtest = 0; subtest < total; subtest++) {
+		for (i = 0; i < nr_bos[subtest]; i++)
+			handles[i] = create_userptr_bo(fd, BO_SIZE);
+
+		if (nr_bos[subtest] > 0)
+			ptr = get_handle_ptr(handles[0]);
+		else
+			ptr = buffer;
+
+		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_read(ptr);
+
+		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
+		test_ptr_write(ptr);
+
+		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(0);
+		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
+		test_malloc_free(1);
+
+		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(0);
+		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
+		test_malloc_realloc_free(1);
+
+		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(0);
+		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
+		test_mmap_unmap(1);
+
+		for (i = 0; i < nr_bos[subtest]; i++)
+			free_userptr_bo(fd, handles[i]);
+	}
+}
+
+static void test_single(int fd)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handle = 0;
+	unsigned long iter = 0;
+	int ret;
+	unsigned long map_size = BO_SIZE + PAGE_SIZE - 1;
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		ret = gem_userptr(fd, bo_ptr, BO_SIZE, 0, &handle);
+		assert(ret == 0);
+		gem_close(fd, handle);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter / test_duration_sec);
+}
+
+static void test_multiple(int fd, unsigned int batch, int random)
+{
+	char *ptr, *bo_ptr;
+	uint32_t handles[10000];
+	int map[10000];
+	unsigned long iter = 0;
+	int ret;
+	int i;
+	unsigned long map_size = batch * BO_SIZE + PAGE_SIZE - 1;
+
+	assert(batch < (sizeof(handles) / sizeof(handles[0])));
+	assert(batch < (sizeof(map) / sizeof(map[0])));
+
+	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	assert(ptr != MAP_FAILED);
+
+	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
+
+	for (i = 0; i < batch; i++)
+		map[i] = i;
+
+	start_test(test_duration_sec);
+
+	while (run_test) {
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++) {
+			ret = gem_userptr(fd, bo_ptr + map[i] * BO_SIZE,
+						BO_SIZE,
+						0, &handles[i]);
+			assert(ret == 0);
+		}
+		if (random)
+			igt_permute_array(map, batch, igt_exchange_int);
+		for (i = 0; i < batch; i++)
+			gem_close(fd, handles[map[i]]);
+		iter++;
+	}
+
+	munmap(ptr, map_size);
+
+	printf("%8lu iter/s\n", iter * batch / test_duration_sec);
+}
+
+static void test_userptr(int fd)
+{
+	printf("create-destroy                = ");
+	test_single(fd);
+
+	printf("multi-create-destroy          = ");
+	test_multiple(fd, 100, 0);
+
+	printf("multi-create-destroy-random   = ");
+	test_multiple(fd, 100, 1);
+}
+
+int main(int argc, char **argv)
+{
+	int fd = -1, ret;
+
+	igt_skip_on_simulation();
+
+	igt_subtest_init(argc, argv);
+
+	fd = drm_open_any();
+	igt_assert(fd >= 0);
+
+	ret = has_userptr(fd);
+	igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
+			strerror(errno), ret);
+
+
+	gem_userptr_test_unsynchronized();
+
+	igt_subtest("userptr-unsync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-unsync")
+		test_impact(fd);
+
+	gem_userptr_test_synchronized();
+
+	igt_subtest("userptr-sync")
+		test_userptr(fd);
+
+	igt_subtest("userptr-impact-sync")
+		test_impact(fd);
+
+	igt_exit();
+
+	return 0;
+}
-- 
1.9.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-04-23 17:17     ` Volkin, Bradley D
@ 2014-04-24  9:08       ` Tvrtko Ursulin
  0 siblings, 0 replies; 28+ messages in thread
From: Tvrtko Ursulin @ 2014-04-24  9:08 UTC (permalink / raw)
  To: Volkin, Bradley D; +Cc: Intel-gfx


On 04/23/2014 06:17 PM, Volkin, Bradley D wrote:
[snip]
>> +static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
>> +{
>> +	struct local_i915_gem_userptr userptr;
>> +	int ret;
>> +
>> +	userptr.user_ptr = (uintptr_t)ptr;
>> +	userptr.user_size = size;
>> +	userptr.flags = userptr_flags;
>> +	if (read_only)
>> +		userptr.flags |= LOCAL_I915_USERPTR_READ_ONLY;
>> +
>> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
>> +	if (ret)
>> +		ret = errno;
>> +	igt_skip_on_f(ret == ENODEV &&
>> +		      (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) == 0,
>> +		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
>
> I missed it the first time around, but the condition here doesn't
> match the other test; it's missing the '&& !read_only'. It looks
> like read_only will always be 0 in this test though, so probably
> not an issue.
>
> Reviewed-by: Brad Volkin <bradley.d.volkin@intel.com>

Good catch! It does not matter in the benchmark but I've sent a respin 
for consistency and clarity.

Thanks,

Tvrtko

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact
  2014-04-24  9:07 ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
@ 2014-04-24 16:07   ` Volkin, Bradley D
  0 siblings, 0 replies; 28+ messages in thread
From: Volkin, Bradley D @ 2014-04-24 16:07 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: Intel-gfx

Reviewed-by: Brad Volkin <bradley.d.volkin@intel.com>

On Thu, Apr 24, 2014 at 10:07:32AM +0100, Tvrtko Ursulin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> This adds a small benchmark for the new userptr functionality.
> 
> Apart from basic surface creation and destruction, also tested is the
> impact of having userptr surfaces in the process address space. Reason
> for that is the impact of MMU notifiers on common address space
> operations like munmap() which is per process.
> 
> v2:
>   * Moved to benchmarks.
>   * Added pointer read/write tests.
>   * Changed output to say iterations per second instead of
>     operations per second.
>   * Multiply result by batch size for multi-create* tests
>     for a more comparable number with create-destroy test.
> 
> v3:
>   * Use ALIGN macro.
>   * Catchup with big lib/ reorganization.
>   * Removed unused code and one global variable.
>   * Fixed up some warnings.
> 
> v4:
>   * Fixed feature test, does not matter here but makes it
>     consistent with gem_userptr_blits and clearer.
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Brad Volkin <bradley.d.volkin@intel.com>
> ---
>  benchmarks/.gitignore              |   1 +
>  benchmarks/Makefile.sources        |   3 +-
>  benchmarks/gem_userptr_benchmark.c | 498 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 501 insertions(+), 1 deletion(-)
>  create mode 100644 benchmarks/gem_userptr_benchmark.c
> 
> diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
> index ddea6f7..09e5bd8 100644
> --- a/benchmarks/.gitignore
> +++ b/benchmarks/.gitignore
> @@ -1,3 +1,4 @@
> +gem_userptr_benchmark
>  intel_upload_blit_large
>  intel_upload_blit_large_gtt
>  intel_upload_blit_large_map
> diff --git a/benchmarks/Makefile.sources b/benchmarks/Makefile.sources
> index f9da579..60bdae2 100644
> --- a/benchmarks/Makefile.sources
> +++ b/benchmarks/Makefile.sources
> @@ -2,4 +2,5 @@ bin_PROGRAMS =                          \
>  	intel_upload_blit_large         \
>  	intel_upload_blit_large_gtt     \
>  	intel_upload_blit_large_map     \
> -	intel_upload_blit_small
> +	intel_upload_blit_small		\
> +	gem_userptr_benchmark
> diff --git a/benchmarks/gem_userptr_benchmark.c b/benchmarks/gem_userptr_benchmark.c
> new file mode 100644
> index 0000000..9ad6e4a
> --- /dev/null
> +++ b/benchmarks/gem_userptr_benchmark.c
> @@ -0,0 +1,498 @@
> +/*
> + * Copyright © 2014 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> + *
> + */
> +
> +/** @file gem_userptr_benchmark.c
> + *
> + * Benchmark the userptr code and impact of having userptr surfaces
> + * in process address space on some normal operations.
> + *
> + */
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <errno.h>
> +#include <assert.h>
> +#include <sys/stat.h>
> +#include <sys/time.h>
> +#include <sys/mman.h>
> +#include "drm.h"
> +#include "i915_drm.h"
> +#include "drmtest.h"
> +#include "intel_bufmgr.h"
> +#include "intel_batchbuffer.h"
> +#include "intel_chipset.h"
> +#include "ioctl_wrappers.h"
> +#include "igt_aux.h"
> +
> +#ifndef PAGE_SIZE
> +  #define PAGE_SIZE 4096
> +#endif
> +
> +#define LOCAL_I915_GEM_USERPTR       0x34
> +#define LOCAL_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_USERPTR, struct local_i915_gem_userptr)
> +struct local_i915_gem_userptr {
> +	uint64_t user_ptr;
> +	uint64_t user_size;
> +	uint32_t flags;
> +#define LOCAL_I915_USERPTR_READ_ONLY (1<<0)
> +#define LOCAL_I915_USERPTR_UNSYNCHRONIZED (1<<31)
> +	uint32_t handle;
> +};
> +
> +static uint32_t userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
> +
> +#define BO_SIZE (65536)
> +
> +static void gem_userptr_test_unsynchronized(void)
> +{
> +	userptr_flags = LOCAL_I915_USERPTR_UNSYNCHRONIZED;
> +}
> +
> +static void gem_userptr_test_synchronized(void)
> +{
> +	userptr_flags = 0;
> +}
> +
> +static int gem_userptr(int fd, void *ptr, int size, int read_only, uint32_t *handle)
> +{
> +	struct local_i915_gem_userptr userptr;
> +	int ret;
> +
> +	userptr.user_ptr = (uintptr_t)ptr;
> +	userptr.user_size = size;
> +	userptr.flags = userptr_flags;
> +	if (read_only)
> +		userptr.flags |= LOCAL_I915_USERPTR_READ_ONLY;
> +
> +	ret = drmIoctl(fd, LOCAL_IOCTL_I915_GEM_USERPTR, &userptr);
> +	if (ret)
> +		ret = errno;
> +	igt_skip_on_f(ret == ENODEV &&
> +		      (userptr_flags & LOCAL_I915_USERPTR_UNSYNCHRONIZED) == 0 &&
> +		      !read_only,
> +		      "Skipping, synchronized mappings with no kernel CONFIG_MMU_NOTIFIER?");
> +	if (ret == 0)
> +		*handle = userptr.handle;
> +
> +	return ret;
> +}
> +
> +static void **handle_ptr_map;
> +static unsigned int num_handle_ptr_map;
> +
> +static void add_handle_ptr(uint32_t handle, void *ptr)
> +{
> +	if (handle >= num_handle_ptr_map) {
> +		handle_ptr_map = realloc(handle_ptr_map,
> +					 (handle + 1000) * sizeof(void*));
> +		num_handle_ptr_map = handle + 1000;
> +	}
> +
> +	handle_ptr_map[handle] = ptr;
> +}
> +
> +static void *get_handle_ptr(uint32_t handle)
> +{
> +	return handle_ptr_map[handle];
> +}
> +
> +static void free_handle_ptr(uint32_t handle)
> +{
> +	igt_assert(handle < num_handle_ptr_map);
> +	igt_assert(handle_ptr_map[handle]);
> +
> +	free(handle_ptr_map[handle]);
> +	handle_ptr_map[handle] = NULL;
> +}
> +
> +static uint32_t create_userptr_bo(int fd, int size)
> +{
> +	void *ptr;
> +	uint32_t handle;
> +	int ret;
> +
> +	ret = posix_memalign(&ptr, PAGE_SIZE, size);
> +	igt_assert(ret == 0);
> +
> +	ret = gem_userptr(fd, (uint32_t *)ptr, size, 0, &handle);
> +	igt_assert(ret == 0);
> +	add_handle_ptr(handle, ptr);
> +
> +	return handle;
> +}
> +
> +static void free_userptr_bo(int fd, uint32_t handle)
> +{
> +	gem_close(fd, handle);
> +	free_handle_ptr(handle);
> +}
> +
> +static int has_userptr(int fd)
> +{
> +	uint32_t handle = 0;
> +	void *ptr;
> +	uint32_t oldflags;
> +	int ret;
> +
> +	assert(posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE) == 0);
> +	oldflags = userptr_flags;
> +	gem_userptr_test_unsynchronized();
> +	ret = gem_userptr(fd, ptr, PAGE_SIZE, 0, &handle);
> +	userptr_flags = oldflags;
> +	if (ret != 0) {
> +		free(ptr);
> +		return 0;
> +	}
> +
> +	gem_close(fd, handle);
> +	free(ptr);
> +
> +	return handle != 0;
> +}
> +
> +static const unsigned int nr_bos[] = {0, 1, 10, 100, 1000};
> +static const unsigned int test_duration_sec = 3;
> +
> +static volatile unsigned int run_test;
> +
> +static void alarm_handler(int sig)
> +{
> +	assert(run_test == 1);
> +	run_test = 0;
> +}
> +
> +static void start_test(unsigned int duration)
> +{
> +	run_test = 1;
> +	if (duration == 0)
> +		duration = test_duration_sec;
> +	signal(SIGALRM, alarm_handler);
> +	alarm(duration);
> +}
> +
> +static void exchange_ptr(void *array, unsigned i, unsigned j)
> +{
> +	void **arr, *tmp;
> +	arr = (void **)array;
> +
> +	tmp = arr[i];
> +	arr[i] = arr[j];
> +	arr[j] = tmp;
> +}
> +
> +static void test_malloc_free(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = malloc(1000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			free(ptr[i]);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_malloc_realloc_free(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = malloc(1000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = realloc(ptr[i], 2000);
> +			assert(ptr[i]);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			free(ptr[i]);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_mmap_unmap(int random)
> +{
> +	unsigned long iter = 0;
> +	unsigned int i, tot = 1000;
> +	void *ptr[tot];
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		for (i = 0; i < tot; i++) {
> +			ptr[i] = mmap(NULL, 1000, PROT_READ | PROT_WRITE,
> +					MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +			assert(ptr[i] != MAP_FAILED);
> +		}
> +		if (random)
> +			igt_permute_array(ptr, tot, exchange_ptr);
> +		for (i = 0; i < tot; i++)
> +			munmap(ptr[i], 1000);
> +		iter++;
> +	}
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_ptr_read(void *ptr)
> +{
> +	unsigned long iter = 0;
> +	volatile unsigned long *p;
> +	unsigned long i, loops;
> +	register unsigned long v;
> +
> +	loops = BO_SIZE / sizeof(unsigned long) / 4;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		p = (unsigned long *)ptr;
> +		for (i = 0; i < loops; i++) {
> +			v = *p++;
> +			v = *p++;
> +			v = *p++;
> +			v = *p++;
> +		}
> +		iter++;
> +	}
> +
> +	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
> +}
> +
> +static void test_ptr_write(void *ptr)
> +{
> +	unsigned long iter = 0;
> +	volatile unsigned long *p;
> +	register unsigned long i, loops;
> +
> +	loops = BO_SIZE / sizeof(unsigned long) / 4;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		p = (unsigned long *)ptr;
> +		for (i = 0; i < loops; i++) {
> +			*p++ = i;
> +			*p++ = i;
> +			*p++ = i;
> +			*p++ = i;
> +		}
> +		iter++;
> +	}
> +
> +	printf("%8lu MB/s\n", iter / test_duration_sec * BO_SIZE / 1000000);
> +}
> +
> +static void test_impact(int fd)
> +{
> +	unsigned int total = sizeof(nr_bos) / sizeof(nr_bos[0]);
> +	unsigned int subtest, i;
> +	uint32_t handles[nr_bos[total-1]];
> +	void *ptr;
> +	char buffer[BO_SIZE];
> +
> +	for (subtest = 0; subtest < total; subtest++) {
> +		for (i = 0; i < nr_bos[subtest]; i++)
> +			handles[i] = create_userptr_bo(fd, BO_SIZE);
> +
> +		if (nr_bos[subtest] > 0)
> +			ptr = get_handle_ptr(handles[0]);
> +		else
> +			ptr = buffer;
> +
> +		printf("ptr-read,                   %5u bos = ", nr_bos[subtest]);
> +		test_ptr_read(ptr);
> +
> +		printf("ptr-write                   %5u bos = ", nr_bos[subtest]);
> +		test_ptr_write(ptr);
> +
> +		printf("malloc-free,                %5u bos = ", nr_bos[subtest]);
> +		test_malloc_free(0);
> +		printf("malloc-free-random          %5u bos = ", nr_bos[subtest]);
> +		test_malloc_free(1);
> +
> +		printf("malloc-realloc-free,        %5u bos = ", nr_bos[subtest]);
> +		test_malloc_realloc_free(0);
> +		printf("malloc-realloc-free-random, %5u bos = ", nr_bos[subtest]);
> +		test_malloc_realloc_free(1);
> +
> +		printf("mmap-unmap,                 %5u bos = ", nr_bos[subtest]);
> +		test_mmap_unmap(0);
> +		printf("mmap-unmap-random,          %5u bos = ", nr_bos[subtest]);
> +		test_mmap_unmap(1);
> +
> +		for (i = 0; i < nr_bos[subtest]; i++)
> +			free_userptr_bo(fd, handles[i]);
> +	}
> +}
> +
> +static void test_single(int fd)
> +{
> +	char *ptr, *bo_ptr;
> +	uint32_t handle = 0;
> +	unsigned long iter = 0;
> +	int ret;
> +	unsigned long map_size = BO_SIZE + PAGE_SIZE - 1;
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		ret = gem_userptr(fd, bo_ptr, BO_SIZE, 0, &handle);
> +		assert(ret == 0);
> +		gem_close(fd, handle);
> +		iter++;
> +	}
> +
> +	munmap(ptr, map_size);
> +
> +	printf("%8lu iter/s\n", iter / test_duration_sec);
> +}
> +
> +static void test_multiple(int fd, unsigned int batch, int random)
> +{
> +	char *ptr, *bo_ptr;
> +	uint32_t handles[10000];
> +	int map[10000];
> +	unsigned long iter = 0;
> +	int ret;
> +	int i;
> +	unsigned long map_size = batch * BO_SIZE + PAGE_SIZE - 1;
> +
> +	assert(batch < (sizeof(handles) / sizeof(handles[0])));
> +	assert(batch < (sizeof(map) / sizeof(map[0])));
> +
> +	ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
> +			MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +	assert(ptr != MAP_FAILED);
> +
> +	bo_ptr = (char *)ALIGN((unsigned long)ptr, PAGE_SIZE);
> +
> +	for (i = 0; i < batch; i++)
> +		map[i] = i;
> +
> +	start_test(test_duration_sec);
> +
> +	while (run_test) {
> +		if (random)
> +			igt_permute_array(map, batch, igt_exchange_int);
> +		for (i = 0; i < batch; i++) {
> +			ret = gem_userptr(fd, bo_ptr + map[i] * BO_SIZE,
> +						BO_SIZE,
> +						0, &handles[i]);
> +			assert(ret == 0);
> +		}
> +		if (random)
> +			igt_permute_array(map, batch, igt_exchange_int);
> +		for (i = 0; i < batch; i++)
> +			gem_close(fd, handles[map[i]]);
> +		iter++;
> +	}
> +
> +	munmap(ptr, map_size);
> +
> +	printf("%8lu iter/s\n", iter * batch / test_duration_sec);
> +}
> +
> +static void test_userptr(int fd)
> +{
> +	printf("create-destroy                = ");
> +	test_single(fd);
> +
> +	printf("multi-create-destroy          = ");
> +	test_multiple(fd, 100, 0);
> +
> +	printf("multi-create-destroy-random   = ");
> +	test_multiple(fd, 100, 1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int fd = -1, ret;
> +
> +	igt_skip_on_simulation();
> +
> +	igt_subtest_init(argc, argv);
> +
> +	fd = drm_open_any();
> +	igt_assert(fd >= 0);
> +
> +	ret = has_userptr(fd);
> +	igt_skip_on_f(ret == 0, "No userptr support - %s (%d)\n",
> +			strerror(errno), ret);
> +
> +
> +	gem_userptr_test_unsynchronized();
> +
> +	igt_subtest("userptr-unsync")
> +		test_userptr(fd);
> +
> +	igt_subtest("userptr-impact-unsync")
> +		test_impact(fd);
> +
> +	gem_userptr_test_synchronized();
> +
> +	igt_subtest("userptr-sync")
> +		test_userptr(fd);
> +
> +	igt_subtest("userptr-impact-sync")
> +		test_impact(fd);
> +
> +	igt_exit();
> +
> +	return 0;
> +}
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2014-04-24 16:07 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-26 16:17 [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
2014-02-26 16:17 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
2014-03-05 14:48   ` Chris Wilson
2014-03-12 13:21     ` Tvrtko Ursulin
2014-02-26 16:17 ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
2014-02-26 16:17 ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
2014-03-19 11:13 ` [PATCH 0/3] tests: New userptr test case Tvrtko Ursulin
2014-03-19 11:13   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
2014-04-18 17:10     ` Volkin, Bradley D
2014-04-23 13:33       ` Tvrtko Ursulin
2014-04-23 15:32         ` Volkin, Bradley D
2014-04-23 17:53           ` Daniel Vetter
2014-03-19 11:13   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
2014-04-17 23:20     ` Volkin, Bradley D
2014-03-19 11:13   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
2014-04-17 23:18     ` Volkin, Bradley D
2014-04-22 18:59       ` Daniel Vetter
2014-04-23 13:28       ` Tvrtko Ursulin
2014-04-23 15:24         ` Volkin, Bradley D
2014-04-23 16:38 ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Tvrtko Ursulin
2014-04-23 16:38   ` [PATCH 2/3] tests/gem_vmap_blits: Remove obsolete test case Tvrtko Ursulin
2014-04-23 17:12     ` Volkin, Bradley D
2014-04-23 16:38   ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
2014-04-23 17:17     ` Volkin, Bradley D
2014-04-24  9:08       ` Tvrtko Ursulin
2014-04-23 17:24   ` [PATCH 1/3] tests/gem_userptr_blits: Expanded userptr test cases Volkin, Bradley D
2014-04-24  9:07 ` [PATCH 3/3] tests/gem_userptr_benchmark: Benchmarking userptr surfaces and impact Tvrtko Ursulin
2014-04-24 16:07   ` Volkin, Bradley D

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.