Commit 1b90e4a4 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915/selftests: Enable selftesting of busy-stats



A couple of very simple tests to ensure that the basic properties of
per-engine busyness accounting [0% and 100% busy] are faithful.

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200617130916.15261-1-chris@chris-wilson.co.uk
parent 0ff0fc97
Loading
Loading
Loading
Loading
+21 −26
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@

#include "intel_gt_requests.h"
#include "i915_selftest.h"
#include "selftest_engine_heartbeat.h"

static int timeline_sync(struct intel_timeline *tl)
{
@@ -142,24 +143,6 @@ out:
	return err;
}

static void engine_heartbeat_disable(struct intel_engine_cs *engine,
				     unsigned long *saved)
{
	*saved = engine->props.heartbeat_interval_ms;
	engine->props.heartbeat_interval_ms = 0;

	intel_engine_pm_get(engine);
	intel_engine_park_heartbeat(engine);
}

static void engine_heartbeat_enable(struct intel_engine_cs *engine,
				    unsigned long saved)
{
	intel_engine_pm_put(engine);

	engine->props.heartbeat_interval_ms = saved;
}

static int live_idle_flush(void *arg)
{
	struct intel_gt *gt = arg;
@@ -170,11 +153,9 @@ static int live_idle_flush(void *arg)
	/* Check that we can flush the idle barriers */

	for_each_engine(engine, gt, id) {
		unsigned long heartbeat;

		engine_heartbeat_disable(engine, &heartbeat);
		st_engine_heartbeat_disable(engine);
		err = __live_idle_pulse(engine, intel_engine_flush_barriers);
		engine_heartbeat_enable(engine, heartbeat);
		st_engine_heartbeat_enable(engine);
		if (err)
			break;
	}
@@ -192,11 +173,9 @@ static int live_idle_pulse(void *arg)
	/* Check that heartbeat pulses flush the idle barriers */

	for_each_engine(engine, gt, id) {
		unsigned long heartbeat;

		engine_heartbeat_disable(engine, &heartbeat);
		st_engine_heartbeat_disable(engine);
		err = __live_idle_pulse(engine, intel_engine_pulse);
		engine_heartbeat_enable(engine, heartbeat);
		st_engine_heartbeat_enable(engine);
		if (err && err != -ENODEV)
			break;

@@ -394,3 +373,19 @@ int intel_heartbeat_live_selftests(struct drm_i915_private *i915)
	i915_modparams.enable_hangcheck = saved_hangcheck;
	return err;
}

void st_engine_heartbeat_disable(struct intel_engine_cs *engine)
{
	engine->props.heartbeat_interval_ms = 0;

	intel_engine_pm_get(engine);
	intel_engine_park_heartbeat(engine);
}

void st_engine_heartbeat_enable(struct intel_engine_cs *engine)
{
	intel_engine_pm_put(engine);

	engine->props.heartbeat_interval_ms =
		engine->defaults.heartbeat_interval_ms;
}
+14 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT */
/*
 * Copyright © 2020 Intel Corporation
 */

#ifndef SELFTEST_ENGINE_HEARTBEAT_H
#define SELFTEST_ENGINE_HEARTBEAT_H

struct intel_engine_cs;

void st_engine_heartbeat_disable(struct intel_engine_cs *engine);
void st_engine_heartbeat_enable(struct intel_engine_cs *engine);

#endif /* SELFTEST_ENGINE_HEARTBEAT_H */
+103 −0
Original line number Diff line number Diff line
@@ -6,7 +6,109 @@

#include "i915_selftest.h"
#include "selftest_engine.h"
#include "selftest_engine_heartbeat.h"
#include "selftests/igt_atomic.h"
#include "selftests/igt_flush_test.h"
#include "selftests/igt_spinner.h"

static int live_engine_busy_stats(void *arg)
{
	struct intel_gt *gt = arg;
	struct intel_engine_cs *engine;
	enum intel_engine_id id;
	struct igt_spinner spin;
	int err = 0;

	/*
	 * Check that if an engine supports busy-stats, they tell the truth.
	 */

	if (igt_spinner_init(&spin, gt))
		return -ENOMEM;

	GEM_BUG_ON(intel_gt_pm_is_awake(gt));
	for_each_engine(engine, gt, id) {
		struct i915_request *rq;
		ktime_t de;
		u64 dt;

		if (!intel_engine_supports_stats(engine))
			continue;

		if (!intel_engine_can_store_dword(engine))
			continue;

		if (intel_gt_pm_wait_for_idle(gt)) {
			err = -EBUSY;
			break;
		}

		st_engine_heartbeat_disable(engine);

		ENGINE_TRACE(engine, "measuring idle time\n");
		preempt_disable();
		dt = ktime_to_ns(ktime_get());
		de = intel_engine_get_busy_time(engine);
		udelay(100);
		de = ktime_sub(intel_engine_get_busy_time(engine), de);
		dt = ktime_to_ns(ktime_get()) - dt;
		preempt_enable();
		if (de < 0 || de > 10) {
			pr_err("%s: reported %lldns [%d%%] busyness while sleeping [for %lldns]\n",
			       engine->name,
			       de, (int)div64_u64(100 * de, dt), dt);
			GEM_TRACE_DUMP();
			err = -EINVAL;
			goto end;
		}

		/* 100% busy */
		rq = igt_spinner_create_request(&spin,
						engine->kernel_context,
						MI_NOOP);
		if (IS_ERR(rq)) {
			err = PTR_ERR(rq);
			goto end;
		}
		i915_request_add(rq);

		if (!igt_wait_for_spinner(&spin, rq)) {
			intel_gt_set_wedged(engine->gt);
			err = -ETIME;
			goto end;
		}

		ENGINE_TRACE(engine, "measuring busy time\n");
		preempt_disable();
		dt = ktime_to_ns(ktime_get());
		de = intel_engine_get_busy_time(engine);
		udelay(100);
		de = ktime_sub(intel_engine_get_busy_time(engine), de);
		dt = ktime_to_ns(ktime_get()) - dt;
		preempt_enable();
		if (100 * de < 95 * dt || 95 * de > 100 * dt) {
			pr_err("%s: reported %lldns [%d%%] busyness while spinning [for %lldns]\n",
			       engine->name,
			       de, (int)div64_u64(100 * de, dt), dt);
			GEM_TRACE_DUMP();
			err = -EINVAL;
			goto end;
		}

end:
		st_engine_heartbeat_enable(engine);
		igt_spinner_end(&spin);
		if (igt_flush_test(gt->i915))
			err = -EIO;
		if (err)
			break;
	}

	igt_spinner_fini(&spin);
	if (igt_flush_test(gt->i915))
		err = -EIO;
	return err;
}

static int live_engine_pm(void *arg)
{
@@ -77,6 +179,7 @@ static int live_engine_pm(void *arg)
int live_engine_pm_selftests(struct intel_gt *gt)
{
	static const struct i915_subtest tests[] = {
		SUBTEST(live_engine_busy_stats),
		SUBTEST(live_engine_pm),
	};

+7 −22
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "intel_gt.h"
#include "intel_engine_heartbeat.h"
#include "intel_engine_pm.h"
#include "selftest_engine_heartbeat.h"

#include "i915_selftest.h"
#include "selftests/i915_random.h"
@@ -310,22 +311,6 @@ static bool wait_until_running(struct hang *h, struct i915_request *rq)
			  1000));
}

static void engine_heartbeat_disable(struct intel_engine_cs *engine)
{
	engine->props.heartbeat_interval_ms = 0;

	intel_engine_pm_get(engine);
	intel_engine_park_heartbeat(engine);
}

static void engine_heartbeat_enable(struct intel_engine_cs *engine)
{
	intel_engine_pm_put(engine);

	engine->props.heartbeat_interval_ms =
		engine->defaults.heartbeat_interval_ms;
}

static int igt_hang_sanitycheck(void *arg)
{
	struct intel_gt *gt = arg;
@@ -482,7 +467,7 @@ static int igt_reset_nop_engine(void *arg)
		reset_engine_count = i915_reset_engine_count(global, engine);
		count = 0;

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		set_bit(I915_RESET_ENGINE + id, &gt->reset.flags);
		do {
			int i;
@@ -540,7 +525,7 @@ static int igt_reset_nop_engine(void *arg)
			}
		} while (time_before(jiffies, end_time));
		clear_bit(I915_RESET_ENGINE + id, &gt->reset.flags);
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);

		pr_info("%s(%s): %d resets\n", __func__, engine->name, count);

@@ -590,7 +575,7 @@ static int __igt_reset_engine(struct intel_gt *gt, bool active)
		reset_count = i915_reset_count(global);
		reset_engine_count = i915_reset_engine_count(global, engine);

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		set_bit(I915_RESET_ENGINE + id, &gt->reset.flags);
		do {
			if (active) {
@@ -642,7 +627,7 @@ static int __igt_reset_engine(struct intel_gt *gt, bool active)
			}
		} while (time_before(jiffies, end_time));
		clear_bit(I915_RESET_ENGINE + id, &gt->reset.flags);
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);

		if (err)
			break;
@@ -841,7 +826,7 @@ static int __igt_reset_engines(struct intel_gt *gt,

		yield(); /* start all threads before we begin */

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		set_bit(I915_RESET_ENGINE + id, &gt->reset.flags);
		do {
			struct i915_request *rq = NULL;
@@ -931,7 +916,7 @@ static int __igt_reset_engines(struct intel_gt *gt,
			}
		} while (time_before(jiffies, end_time));
		clear_bit(I915_RESET_ENGINE + id, &gt->reset.flags);
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);

		pr_info("i915_reset_engine(%s:%s): %lu resets\n",
			engine->name, test_name, count);
+32 −47
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "gem/i915_gem_pm.h"
#include "gt/intel_engine_heartbeat.h"
#include "gt/intel_reset.h"
#include "gt/selftest_engine_heartbeat.h"

#include "i915_selftest.h"
#include "selftests/i915_random.h"
@@ -51,22 +52,6 @@ static struct i915_vma *create_scratch(struct intel_gt *gt)
	return vma;
}

static void engine_heartbeat_disable(struct intel_engine_cs *engine)
{
	engine->props.heartbeat_interval_ms = 0;

	intel_engine_pm_get(engine);
	intel_engine_park_heartbeat(engine);
}

static void engine_heartbeat_enable(struct intel_engine_cs *engine)
{
	intel_engine_pm_put(engine);

	engine->props.heartbeat_interval_ms =
		engine->defaults.heartbeat_interval_ms;
}

static bool is_active(struct i915_request *rq)
{
	if (i915_request_is_active(rq))
@@ -234,7 +219,7 @@ static int live_unlite_restore(struct intel_gt *gt, int prio)
			err = -EIO;
			break;
		}
		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);

		for (n = 0; n < ARRAY_SIZE(ce); n++) {
			struct intel_context *tmp;
@@ -342,7 +327,7 @@ err_ce:
			intel_context_put(ce[n]);
		}

		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (igt_live_test_end(&t))
			err = -EIO;
		if (err)
@@ -396,7 +381,7 @@ static int live_unlite_ring(void *arg)
			err = -EIO;
			break;
		}
		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);

		for (n = 0; n < ARRAY_SIZE(ce); n++) {
			struct intel_context *tmp;
@@ -502,7 +487,7 @@ err_ce:
			intel_context_unpin(ce[n]);
			intel_context_put(ce[n]);
		}
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (igt_live_test_end(&t))
			err = -EIO;
		if (err)
@@ -621,7 +606,7 @@ static int live_hold_reset(void *arg)
			break;
		}

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);

		rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
		if (IS_ERR(rq)) {
@@ -681,7 +666,7 @@ static int live_hold_reset(void *arg)
		i915_request_put(rq);

out:
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		intel_context_put(ce);
		if (err)
			break;
@@ -728,7 +713,7 @@ static int live_error_interrupt(void *arg)
		const struct error_phase *p;
		int err = 0;

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);

		for (p = phases; p->error[0] != GOOD; p++) {
			struct i915_request *client[ARRAY_SIZE(phases->error)];
@@ -827,7 +812,7 @@ out:
			}
		}

		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (err) {
			intel_gt_set_wedged(gt);
			return err;
@@ -1042,9 +1027,9 @@ static int live_timeslice_preempt(void *arg)

		memset(vaddr, 0, PAGE_SIZE);

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		err = slice_semaphore_queue(engine, vma, 5);
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (err)
			goto err_pin;

@@ -1166,7 +1151,7 @@ static int live_timeslice_rewind(void *arg)
		 * Expect execution/evaluation order XZY
		 */

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		timeslice = xchg(&engine->props.timeslice_duration_ms, 1);

		slot = memset32(engine->status_page.addr + 1000, 0, 4);
@@ -1261,7 +1246,7 @@ err:
		wmb();

		engine->props.timeslice_duration_ms = timeslice;
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		for (i = 0; i < 3; i++)
			i915_request_put(rq[i]);
		if (igt_flush_test(gt->i915))
@@ -1353,7 +1338,7 @@ static int live_timeslice_queue(void *arg)
		if (!intel_engine_has_preemption(engine))
			continue;

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		memset(vaddr, 0, PAGE_SIZE);

		/* ELSP[0]: semaphore wait */
@@ -1414,7 +1399,7 @@ static int live_timeslice_queue(void *arg)
err_rq:
		i915_request_put(rq);
err_heartbeat:
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (err)
			break;
	}
@@ -1460,7 +1445,7 @@ static int live_timeslice_nopreempt(void *arg)
			break;
		}

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		timeslice = xchg(&engine->props.timeslice_duration_ms, 1);

		/* Create an unpreemptible spinner */
@@ -1529,7 +1514,7 @@ out_spin:
		igt_spinner_end(&spin);
out_heartbeat:
		xchg(&engine->props.timeslice_duration_ms, timeslice);
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (err)
			break;

@@ -2433,7 +2418,7 @@ static int live_suppress_self_preempt(void *arg)
		if (igt_flush_test(gt->i915))
			goto err_wedged;

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);
		engine->execlists.preempt_hang.count = 0;

		rq_a = spinner_create_request(&a.spin,
@@ -2441,14 +2426,14 @@ static int live_suppress_self_preempt(void *arg)
					      MI_NOOP);
		if (IS_ERR(rq_a)) {
			err = PTR_ERR(rq_a);
			engine_heartbeat_enable(engine);
			st_engine_heartbeat_enable(engine);
			goto err_client_b;
		}

		i915_request_add(rq_a);
		if (!igt_wait_for_spinner(&a.spin, rq_a)) {
			pr_err("First client failed to start\n");
			engine_heartbeat_enable(engine);
			st_engine_heartbeat_enable(engine);
			goto err_wedged;
		}

@@ -2460,7 +2445,7 @@ static int live_suppress_self_preempt(void *arg)
						      MI_NOOP);
			if (IS_ERR(rq_b)) {
				err = PTR_ERR(rq_b);
				engine_heartbeat_enable(engine);
				st_engine_heartbeat_enable(engine);
				goto err_client_b;
			}
			i915_request_add(rq_b);
@@ -2471,7 +2456,7 @@ static int live_suppress_self_preempt(void *arg)

			if (!igt_wait_for_spinner(&b.spin, rq_b)) {
				pr_err("Second client failed to start\n");
				engine_heartbeat_enable(engine);
				st_engine_heartbeat_enable(engine);
				goto err_wedged;
			}

@@ -2485,12 +2470,12 @@ static int live_suppress_self_preempt(void *arg)
			       engine->name,
			       engine->execlists.preempt_hang.count,
			       depth);
			engine_heartbeat_enable(engine);
			st_engine_heartbeat_enable(engine);
			err = -EINVAL;
			goto err_client_b;
		}

		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (igt_flush_test(gt->i915))
			goto err_wedged;
	}
@@ -2902,7 +2887,7 @@ static int live_preempt_ring(void *arg)
		if (!intel_engine_can_store_dword(engine))
			continue;

		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);

		for (n = 0; n <= 3; n++) {
			err = __live_preempt_ring(engine, &spin,
@@ -2911,7 +2896,7 @@ static int live_preempt_ring(void *arg)
				break;
		}

		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (err)
			break;
	}
@@ -4568,7 +4553,7 @@ static int reset_virtual_engine(struct intel_gt *gt,
	}

	for (n = 0; n < nsibling; n++)
		engine_heartbeat_disable(siblings[n]);
		st_engine_heartbeat_disable(siblings[n]);

	rq = igt_spinner_create_request(&spin, ve, MI_ARB_CHECK);
	if (IS_ERR(rq)) {
@@ -4639,7 +4624,7 @@ out_rq:
	i915_request_put(rq);
out_heartbeat:
	for (n = 0; n < nsibling; n++)
		engine_heartbeat_enable(siblings[n]);
		st_engine_heartbeat_enable(siblings[n]);

	intel_context_put(ve);
out_spin:
@@ -5314,7 +5299,7 @@ static int live_lrc_gpr(void *arg)
		return PTR_ERR(scratch);

	for_each_engine(engine, gt, id) {
		engine_heartbeat_disable(engine);
		st_engine_heartbeat_disable(engine);

		err = __live_lrc_gpr(engine, scratch, false);
		if (err)
@@ -5325,7 +5310,7 @@ static int live_lrc_gpr(void *arg)
			goto err;

err:
		engine_heartbeat_enable(engine);
		st_engine_heartbeat_enable(engine);
		if (igt_flush_test(gt->i915))
			err = -EIO;
		if (err)
@@ -5474,7 +5459,7 @@ static int live_lrc_timestamp(void *arg)
	for_each_engine(data.engine, gt, id) {
		int i, err = 0;

		engine_heartbeat_disable(data.engine);
		st_engine_heartbeat_disable(data.engine);

		for (i = 0; i < ARRAY_SIZE(data.ce); i++) {
			struct intel_context *tmp;
@@ -5507,7 +5492,7 @@ static int live_lrc_timestamp(void *arg)
		}

err:
		engine_heartbeat_enable(data.engine);
		st_engine_heartbeat_enable(data.engine);
		for (i = 0; i < ARRAY_SIZE(data.ce); i++) {
			if (!data.ce[i])
				break;
Loading