summaryrefslogtreecommitdiff
path: root/tests/i915/gem_softpin.c
diff options
context:
space:
mode:
authorZbigniew Kempczyński <zbigniew.kempczynski@intel.com>2021-01-14 13:06:56 +0100
committerZbigniew Kempczyński <zbigniew.kempczynski@intel.com>2021-04-13 15:44:38 +0200
commit4552dc3fc3459c49ed0f398094cdf509852b1c42 (patch)
tree08a2396b511bc97e76874bc64af1ca1ded82405c /tests/i915/gem_softpin.c
parentf92db39cf96a31d8371fd0b537b661dd366fa653 (diff)
tests/gem_softpin: Verify allocator and execbuf pair work together
Exercise objects offsets produced by the allocator for execbuf are valid and no EINVAL/ENOSPC occurs. Check it works properly also for multiprocess allocations/execbufs for same context. As we're in full-ppgtt we disable softpin to verify offsets produced by the allocator are valid and kernel doesn't want to relocate them. Add allocator-basic and allocator-basic-reserve to BAT. Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch> Acked-by: Petri Latvala <petri.latvala@intel.com>
Diffstat (limited to 'tests/i915/gem_softpin.c')
-rw-r--r--tests/i915/gem_softpin.c194
1 files changed, 194 insertions, 0 deletions
diff --git a/tests/i915/gem_softpin.c b/tests/i915/gem_softpin.c
index aba060a4..c3bfd10a 100644
--- a/tests/i915/gem_softpin.c
+++ b/tests/i915/gem_softpin.c
@@ -28,6 +28,7 @@
#include "i915/gem.h"
#include "igt.h"
+#include "intel_allocator.h"
#define EXEC_OBJECT_PINNED (1<<4)
#define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3)
@@ -697,6 +698,184 @@ static void test_noreloc(int fd, enum sleep sleep, unsigned flags)
gem_close(fd, object[i].handle);
}
+static void __reserve(uint64_t ahnd, int i915, bool pinned,
+ struct drm_i915_gem_exec_object2 *objects,
+ int num_obj, uint64_t size)
+{
+ uint64_t gtt = gem_aperture_size(i915);
+ unsigned int flags;
+ int i;
+
+ igt_assert(num_obj > 1);
+
+ flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
+ if (pinned)
+ flags |= EXEC_OBJECT_PINNED;
+
+ memset(objects, 0, sizeof(objects) * num_obj);
+
+ for (i = 0; i < num_obj; i++) {
+ objects[i].handle = gem_create(i915, size);
+ if (i < num_obj/2)
+ objects[i].offset = i * size;
+ else
+ objects[i].offset = gtt - (i + 1 - num_obj/2) * size;
+ objects[i].flags = flags;
+
+ intel_allocator_reserve(ahnd, objects[i].handle,
+ size, objects[i].offset);
+ igt_debug("Reserve i: %d, handle: %u, offset: %llx\n", i,
+ objects[i].handle, (long long) objects[i].offset);
+ }
+}
+
+static void __unreserve(uint64_t ahnd, int i915,
+ struct drm_i915_gem_exec_object2 *objects,
+ int num_obj, uint64_t size)
+{
+ int i;
+
+ for (i = 0; i < num_obj; i++) {
+ intel_allocator_unreserve(ahnd, objects[i].handle,
+ size, objects[i].offset);
+ igt_debug("Unreserve i: %d, handle: %u, offset: %llx\n", i,
+ objects[i].handle, (long long) objects[i].offset);
+ gem_close(i915, objects[i].handle);
+ }
+}
+
+static void __exec_using_allocator(uint64_t ahnd, int i915, int num_obj,
+ bool pinned)
+{
+ const uint32_t bbe = MI_BATCH_BUFFER_END;
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 object[num_obj];
+ uint64_t stored_offsets[num_obj];
+ unsigned int flags;
+ uint64_t sz = 4096;
+ int i;
+
+ igt_assert(num_obj > 10);
+
+ flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
+ if (pinned)
+ flags |= EXEC_OBJECT_PINNED;
+
+ memset(object, 0, sizeof(object));
+
+ for (i = 0; i < num_obj; i++) {
+ sz = (rand() % 15 + 1) * 4096;
+ if (i == num_obj - 1)
+ sz = 4096;
+ object[i].handle = gem_create(i915, sz);
+ object[i].offset =
+ intel_allocator_alloc(ahnd, object[i].handle, sz, 0);
+ }
+ gem_write(i915, object[--i].handle, 0, &bbe, sizeof(bbe));
+
+ for (i = 0; i < num_obj; i++) {
+ object[i].flags = flags;
+ object[i].offset = gen8_canonical_addr(object[i].offset);
+ stored_offsets[i] = object[i].offset;
+ }
+
+ memset(&execbuf, 0, sizeof(execbuf));
+ execbuf.buffers_ptr = to_user_pointer(object);
+ execbuf.buffer_count = num_obj;
+ gem_execbuf(i915, &execbuf);
+
+ for (i = 0; i < num_obj; i++) {
+ igt_assert(intel_allocator_free(ahnd, object[i].handle));
+ gem_close(i915, object[i].handle);
+ }
+
+ /* Check kernel will keep offsets even if pinned is not set. */
+ for (i = 0; i < num_obj; i++)
+ igt_assert_eq_u64(stored_offsets[i], object[i].offset);
+}
+
+static void test_allocator_basic(int fd, bool reserve)
+{
+ const int num_obj = 257, num_reserved = 8;
+ struct drm_i915_gem_exec_object2 objects[num_reserved];
+ uint64_t ahnd, ressize = 4096;
+
+ /*
+ * Check that we can place objects at start/end
+ * of the GTT using the allocator.
+ */
+ ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_SIMPLE);
+
+ if (reserve)
+ __reserve(ahnd, fd, true, objects, num_reserved, ressize);
+ __exec_using_allocator(ahnd, fd, num_obj, true);
+ if (reserve)
+ __unreserve(ahnd, fd, objects, num_reserved, ressize);
+ igt_assert(intel_allocator_close(ahnd) == true);
+}
+
+static void test_allocator_nopin(int fd, bool reserve)
+{
+ const int num_obj = 257, num_reserved = 8;
+ struct drm_i915_gem_exec_object2 objects[num_reserved];
+ uint64_t ahnd, ressize = 4096;
+
+ /*
+ * Check that we can combine manual placement with automatic
+ * GTT placement.
+ *
+ * This will also check that we agree with this small sampling of
+ * allocator placements -- that is the given the same restrictions
+ * in execobj[] the kernel does not reject the placement due
+ * to overlaps or invalid addresses.
+ */
+ ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_SIMPLE);
+
+ if (reserve)
+ __reserve(ahnd, fd, false, objects, num_reserved, ressize);
+
+ __exec_using_allocator(ahnd, fd, num_obj, false);
+
+ if (reserve)
+ __unreserve(ahnd, fd, objects, num_reserved, ressize);
+
+ igt_assert(intel_allocator_close(ahnd) == true);
+}
+
+static void test_allocator_fork(int fd)
+{
+ const int num_obj = 17, num_reserved = 8;
+ struct drm_i915_gem_exec_object2 objects[num_reserved];
+ uint64_t ahnd, ressize = 4096;
+
+ /*
+ * Must be called before opening allocator in multiprocess environment
+ * due to freeing previous allocator infrastructure and proper setup
+ * of data structures and allocation thread.
+ */
+ intel_allocator_multiprocess_start();
+
+ ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_SIMPLE);
+ __reserve(ahnd, fd, true, objects, num_reserved, ressize);
+
+ igt_fork(child, 8) {
+ ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_SIMPLE);
+ igt_until_timeout(2)
+ __exec_using_allocator(ahnd, fd, num_obj, true);
+ intel_allocator_close(ahnd);
+ }
+
+ igt_waitchildren();
+
+ __unreserve(ahnd, fd, objects, num_reserved, ressize);
+ igt_assert(intel_allocator_close(ahnd) == true);
+
+ ahnd = intel_allocator_open(fd, 0, INTEL_ALLOCATOR_SIMPLE);
+ igt_assert(intel_allocator_close(ahnd) == true);
+
+ intel_allocator_multiprocess_stop();
+}
+
igt_main
{
int fd = -1;
@@ -727,6 +906,21 @@ igt_main
igt_subtest("full")
test_full(fd);
+
+ igt_subtest("allocator-basic")
+ test_allocator_basic(fd, false);
+
+ igt_subtest("allocator-basic-reserve")
+ test_allocator_basic(fd, true);
+
+ igt_subtest("allocator-nopin")
+ test_allocator_nopin(fd, false);
+
+ igt_subtest("allocator-nopin-reserve")
+ test_allocator_nopin(fd, true);
+
+ igt_subtest("allocator-fork")
+ test_allocator_fork(fd);
}
igt_subtest("softpin")