[Intel-gfx] [CI 07/14] drm/i915/selftests: Exercise priority inheritance around an engine loop

Tvrtko Ursulin tvrtko.ursulin at linux.intel.com
Tue Feb 2 16:44:26 UTC 2021


On 02/02/2021 15:14, Chris Wilson wrote:
> Exercise rescheduling priority inheritance around a sequence of requests
> that wrap around all the engines.
> 
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
>   .../gpu/drm/i915/selftests/i915_scheduler.c   | 225 ++++++++++++++++++
>   1 file changed, 225 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/selftests/i915_scheduler.c b/drivers/gpu/drm/i915/selftests/i915_scheduler.c
> index d095fab2ccec..acc666f755d7 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_scheduler.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_scheduler.c
> @@ -7,6 +7,7 @@
>   
>   #include "gt/intel_context.h"
>   #include "gt/intel_gpu_commands.h"
> +#include "gt/intel_ring.h"
>   #include "gt/selftest_engine_heartbeat.h"
>   #include "selftests/igt_spinner.h"
>   #include "selftests/i915_random.h"
> @@ -504,10 +505,234 @@ static int igt_priority_chains(void *arg)
>   	return igt_schedule_chains(arg, igt_priority);
>   }
>   
> +static struct i915_request *
> +__write_timestamp(struct intel_engine_cs *engine,
> +		  struct drm_i915_gem_object *obj,
> +		  int slot,
> +		  struct i915_request *prev)
> +{
> +	struct i915_request *rq = ERR_PTR(-EINVAL);
> +	bool use_64b = INTEL_GEN(engine->i915) >= 8;
> +	struct intel_context *ce;
> +	struct i915_vma *vma;
> +	int err = 0;
> +	u32 *cs;
> +
> +	ce = intel_context_create(engine);
> +	if (IS_ERR(ce))
> +		return ERR_CAST(ce);
> +
> +	vma = i915_vma_instance(obj, ce->vm, NULL);
> +	if (IS_ERR(vma)) {
> +		err = PTR_ERR(vma);
> +		goto out_ce;
> +	}
> +
> +	err = i915_vma_pin(vma, 0, 0, PIN_USER);
> +	if (err)
> +		goto out_ce;
> +
> +	rq = intel_context_create_request(ce);
> +	if (IS_ERR(rq)) {
> +		err = PTR_ERR(rq);
> +		goto out_unpin;
> +	}
> +
> +	i915_vma_lock(vma);
> +	err = i915_vma_move_to_active(vma, rq, EXEC_OBJECT_WRITE);
> +	i915_vma_unlock(vma);
> +	if (err)
> +		goto out_request;
> +
> +	if (prev) {
> +		err = i915_request_await_dma_fence(rq, &prev->fence);
> +		if (err)
> +			goto out_request;
> +	}
> +
> +	if (engine->emit_init_breadcrumb) {
> +		err = engine->emit_init_breadcrumb(rq);
> +		if (err)
> +			goto out_request;
> +	}
> +
> +	cs = intel_ring_begin(rq, 4);
> +	if (IS_ERR(cs)) {
> +		err = PTR_ERR(cs);
> +		goto out_request;
> +	}
> +
> +	*cs++ = MI_STORE_REGISTER_MEM + use_64b;
> +	*cs++ = i915_mmio_reg_offset(RING_TIMESTAMP(engine->mmio_base));
> +	*cs++ = lower_32_bits(vma->node.start) + sizeof(u32) * slot;
> +	*cs++ = upper_32_bits(vma->node.start);
> +	intel_ring_advance(rq, cs);
> +
> +	i915_request_get(rq);
> +out_request:
> +	i915_request_add(rq);
> +out_unpin:
> +	i915_vma_unpin(vma);
> +out_ce:
> +	intel_context_put(ce);
> +	i915_request_put(prev);
> +	return err ? ERR_PTR(err) : rq;
> +}
> +
> +static struct i915_request *create_spinner(struct drm_i915_private *i915,
> +					   struct igt_spinner *spin)
> +{
> +	struct intel_engine_cs *engine;
> +
> +	for_each_uabi_engine(engine, i915) {
> +		struct intel_context *ce;
> +		struct i915_request *rq;
> +
> +		if (igt_spinner_init(spin, engine->gt))
> +			return ERR_PTR(-ENOMEM);
> +
> +		ce = intel_context_create(engine);
> +		if (IS_ERR(ce))
> +			return ERR_CAST(ce);
> +
> +		rq = igt_spinner_create_request(spin, ce, MI_NOOP);
> +		intel_context_put(ce);
> +		if (rq == ERR_PTR(-ENODEV))
> +			continue;
> +		if (IS_ERR(rq))
> +			return rq;
> +
> +		i915_request_get(rq);
> +		i915_request_add(rq);
> +		return rq;
> +	}
> +
> +	return ERR_PTR(-ENODEV);
> +}
> +
> +static bool has_timestamp(const struct drm_i915_private *i915)
> +{
> +	return INTEL_GEN(i915) >= 7;
> +}
> +
> +static int __igt_schedule_cycle(struct drm_i915_private *i915,
> +				bool (*fn)(struct i915_request *rq,
> +					   unsigned long v, unsigned long e))
> +{
> +	struct intel_engine_cs *engine;
> +	struct drm_i915_gem_object *obj;
> +	struct igt_spinner spin;
> +	struct i915_request *rq;
> +	unsigned long count, n;
> +	u32 *time, last;
> +	int err;
> +
> +	/*
> +	 * Queue a bunch of ordered requests (each waiting on the previous)
> +	 * around the engines a couple of times. Each request will write
> +	 * the timestamp it executes at into the scratch, with the expectation
> +	 * that the timestamp will be in our desired execution order.
> +	 */
> +
> +	if (!i915->caps.scheduler || !has_timestamp(i915))
> +		return 0;
> +
> +	obj = i915_gem_object_create_internal(i915, SZ_64K);
> +	if (IS_ERR(obj))
> +		return PTR_ERR(obj);
> +
> +	time = i915_gem_object_pin_map(obj, I915_MAP_WC);
> +	if (IS_ERR(time)) {
> +		err = PTR_ERR(time);
> +		goto out_obj;
> +	}
> +
> +	rq = create_spinner(i915, &spin);
> +	if (IS_ERR(rq)) {
> +		err = PTR_ERR(rq);
> +		goto out_obj;
> +	}
> +
> +	err = 0;
> +	count = 0;
> +	for_each_uabi_engine(engine, i915) {
> +		if (!intel_engine_has_scheduler(engine))
> +			continue;
> +
> +		rq = __write_timestamp(engine, obj, count, rq);
> +		if (IS_ERR(rq)) {
> +			err = PTR_ERR(rq);
> +			break;
> +		}
> +
> +		count++;
> +	}

^^^^ vvvv - two of the same by copy&paste error or couldn't be bothered 
with outer loop?

> +	for_each_uabi_engine(engine, i915) {
> +		if (!intel_engine_has_scheduler(engine))
> +			continue;
> +
> +		rq = __write_timestamp(engine, obj, count, rq);
> +		if (IS_ERR(rq)) {
> +			err = PTR_ERR(rq);
> +			break;
> +		}
> +
> +		count++;
> +	}
> +	GEM_BUG_ON(count * sizeof(u32) > obj->base.size);
> +	if (err || !count)
> +		goto out_spin;
> +
> +	fn(rq, count + 1, count);
> +	igt_spinner_end(&spin);
> +
> +	if (i915_request_wait(rq, 0, HZ / 2) < 0) {
> +		err = -ETIME;
> +		goto out_request;
> +	}
> +
> +	last = time[0];
> +	for (n = 1; n < count; n++) {
> +		if (i915_seqno_passed(last, time[n])) {
> +			pr_err("Timestamp[%lu] %x before previous %x\n",
> +			       n, time[n], last);
> +			err = -EINVAL;
> +			break;
> +		}
> +		last = time[n];
> +	}
> +
> +out_request:
> +	i915_request_put(rq);
> +out_spin:
> +	igt_spinner_fini(&spin);
> +out_obj:
> +	i915_gem_object_put(obj);
> +	return err;
> +}
> +
> +static bool noop(struct i915_request *rq, unsigned long v, unsigned long e)
> +{
> +	return true;
> +}
> +
> +static int igt_schedule_cycle(void *arg)
> +{
> +	return __igt_schedule_cycle(arg, noop);
> +}
> +
> +static int igt_priority_cycle(void *arg)
> +{
> +	return __igt_schedule_cycle(arg, igt_priority);
> +}
> +
>   int i915_scheduler_live_selftests(struct drm_i915_private *i915)
>   {
>   	static const struct i915_subtest tests[] = {
>   		SUBTEST(igt_priority_chains),
> +
> +		SUBTEST(igt_schedule_cycle),
> +		SUBTEST(igt_priority_cycle),
>   	};
>   
>   	return i915_subtests(tests, i915);
> 

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>

Regards,

Tvrtko


More information about the Intel-gfx mailing list