diff mbox

[30/37] drm/i915: Exercise filling and removing random ranges from the live GTT

Message ID 20170111210937.29252-31-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson Jan. 11, 2017, 9:09 p.m. UTC
Test the low-level i915_address_space interfaces to sanity check the
live insertion/removal of address ranges.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/selftests/i915_gem_gtt.c | 140 ++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)

Comments

Joonas Lahtinen Jan. 13, 2017, 8:59 a.m. UTC | #1
On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> Test the low-level i915_address_space interfaces to sanity check the
> live insertion/removal of address ranges.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

<SNIP>

> +static u64 scale(u64 offset, unsigned int shift)
> +{
> +	return offset << shift;
> +}

BIT_ULL is your friend.

> +static int random_hole(struct drm_i915_private *i915,

fill_random_hole?

> +		       struct i915_address_space *vm,
> +		       u64 hole_start, u64 hole_end)
> +{
> +	I915_RND_STATE(prng);

Just to remind that this prng should be seeded from the user seed to
maintain repeatability. I kinda assume it's so.

> +	unsigned int size;
> +
> +	for (size = 12; (hole_end - hole_start) >> (size + 2); size++) {

This criteria is not obvious to me. Maybe write a comment above.

You could add a variable BIT_ULL(1, size) here too.

<SNIP>

Put a one line comment what each test achieves, again you have some of
it in the commit messages already.

> +static int igt_ppgtt_drunk(void *arg)

Regards, Joonas
Chris Wilson Jan. 13, 2017, 9:08 a.m. UTC | #2
On Fri, Jan 13, 2017 at 10:59:52AM +0200, Joonas Lahtinen wrote:
> On ke, 2017-01-11 at 21:09 +0000, Chris Wilson wrote:
> > +		       struct i915_address_space *vm,
> > +		       u64 hole_start, u64 hole_end)
> > +{
> > +	I915_RND_STATE(prng);
> 
> Just to remind that this prng should be seeded from the user seed to
> maintain repeatability. I kinda assume it's so.

I915_RND_STATE() does the initialisation from the user seed. But as we
were discussing on IRC, since the inner loop has variable length (due to
each being limited by the user timeout), we need to reseed at the
beginning of each loop. As the loops are fairly uniform, we want to
reseed using the prng(user_seed) to try and avoid falling into the trap
of pattern repetition.
-Chris
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
index 68f7bfb7502e..b20406631120 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
@@ -25,6 +25,7 @@ 
 #include <linux/prime_numbers.h>
 
 #include "i915_selftest.h"
+#include "i915_random.h"
 #include "fake_drm.h"
 #include "huge_gem_object.h"
 
@@ -290,6 +291,74 @@  static int walk_hole(struct drm_i915_private *i915,
 	return err;
 }
 
+static u64 scale(u64 offset, unsigned int shift)
+{
+	return offset << shift;
+}
+
+static int random_hole(struct drm_i915_private *i915,
+		       struct i915_address_space *vm,
+		       u64 hole_start, u64 hole_end)
+{
+	I915_RND_STATE(prng);
+	unsigned int size;
+
+	for (size = 12; (hole_end - hole_start) >> (size + 2); size++) {
+		I915_SELFTEST_TIMEOUT(end_time);
+		struct drm_i915_gem_object *obj;
+		unsigned int *order, count, n;
+		u64 hole_size;
+
+		hole_size = (hole_end - hole_start) >> size;
+		if (hole_size > KMALLOC_MAX_SIZE / sizeof(u32))
+			hole_size = KMALLOC_MAX_SIZE / sizeof(u32);
+		count = hole_size;
+		do {
+			count >>= 1;
+			order = i915_random_order(count, &prng);
+		} while (!order && count);
+
+		obj = huge_gem_object(i915, PAGE_SIZE, scale(1, size));
+		if (IS_ERR(obj))
+			break;
+
+		GEM_BUG_ON(obj->base.size != scale(1, size));
+
+		if (i915_gem_object_pin_pages(obj)) {
+			i915_gem_object_put(obj);
+			break;
+		}
+
+		for (n = 0; n < count; n++) {
+			if (vm->allocate_va_range &&
+			    vm->allocate_va_range(vm,
+						  scale(order[n], size),
+						  scale(1, size)))
+				break;
+
+			vm->insert_entries(vm, obj->mm.pages,
+					   scale(order[n], size),
+					   I915_CACHE_NONE, 0);
+			if (time_after(jiffies, end_time))
+				break;
+		}
+		count = n;
+
+		i915_random_reorder(order, count, &prng);
+		for (n = 0; n < count; n++)
+			vm->clear_range(vm,
+					scale(order[n], size),
+					scale(1, size));
+
+		i915_gem_object_unpin_pages(obj);
+		i915_gem_object_put(obj);
+
+		kfree(order);
+	}
+
+	return 0;
+}
+
 static int igt_ppgtt_fill(void *arg)
 {
 	struct drm_i915_private *dev_priv = arg;
@@ -356,6 +425,39 @@  static int igt_ppgtt_walk(void *arg)
 	return err;
 }
 
+static int igt_ppgtt_drunk(void *arg)
+{
+	struct drm_i915_private *dev_priv = arg;
+	struct drm_file *file;
+	struct i915_hw_ppgtt *ppgtt;
+	int err;
+
+	if (!USES_FULL_PPGTT(dev_priv))
+		return 0;
+
+	file = fake_file(dev_priv);
+	if (IS_ERR(file))
+		return PTR_ERR(file);
+
+	mutex_lock(&dev_priv->drm.struct_mutex);
+	ppgtt = i915_ppgtt_create(dev_priv, file->driver_priv, "mock");
+	if (IS_ERR(ppgtt)) {
+		err = PTR_ERR(ppgtt);
+		goto err_unlock;
+	}
+	GEM_BUG_ON(ppgtt->base.total & ~PAGE_MASK);
+
+	err = random_hole(dev_priv, &ppgtt->base, 0, ppgtt->base.total);
+
+	i915_ppgtt_close(&ppgtt->base);
+	i915_ppgtt_put(ppgtt);
+err_unlock:
+	mutex_unlock(&dev_priv->drm.struct_mutex);
+
+	fake_file_free(dev_priv, file);
+	return err;
+}
+
 static int igt_ggtt_fill(void *arg)
 {
 	struct drm_i915_private *i915 = arg;
@@ -428,12 +530,50 @@  static int igt_ggtt_walk(void *arg)
 	return err;
 }
 
+static int igt_ggtt_drunk(void *arg)
+{
+	struct drm_i915_private *i915 = arg;
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 hole_start = U64_MAX, hole_end = 0, hole_size = 0;
+	u64 this_start, this_end;
+	struct drm_mm_node *node;
+	int err;
+
+	GEM_BUG_ON(ggtt->base.total & ~PAGE_MASK);
+
+	mutex_lock(&i915->drm.struct_mutex);
+	drm_mm_for_each_hole(node, &ggtt->base.mm, this_start, this_end) {
+		u64 this_size;
+
+		if (ggtt->base.mm.color_adjust)
+			ggtt->base. mm.color_adjust(node, 0,
+						    &this_start, &this_end);
+
+		this_size = this_end - this_start;
+		if (this_size > hole_size) {
+			hole_size = this_size;
+			hole_start = this_start;
+			hole_end = this_end;
+		}
+	}
+	pr_info("Found GGTT hole [%llx, %llx], size %llx\n",
+		hole_start, hole_end, hole_size);
+	GEM_BUG_ON(hole_start >= hole_end);
+
+	err = random_hole(i915, &ggtt->base, hole_start, hole_end);
+	mutex_unlock(&i915->drm.struct_mutex);
+
+	return err;
+}
+
 int i915_gem_gtt_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
 		SUBTEST(igt_ppgtt_alloc),
+		SUBTEST(igt_ppgtt_drunk),
 		SUBTEST(igt_ppgtt_walk),
 		SUBTEST(igt_ppgtt_fill),
+		SUBTEST(igt_ggtt_drunk),
 		SUBTEST(igt_ggtt_walk),
 		SUBTEST(igt_ggtt_fill),
 	};