[igt-dev] [PATCH i-g-t 2/3] tests/gem_eio: Speed up test execution
Chris Wilson
chris at chris-wilson.co.uk
Thu Mar 22 11:39:15 UTC 2018
Quoting Tvrtko Ursulin (2018-03-22 11:17:11)
> From: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
>
> If we stop relying on regular GPU hangs to be detected, but trigger them
> manually as soon as we know our batch of interest is actually executing
> on the GPU, we can dramatically speed up various subtests.
>
> This is enabled by the pollable spin batch added in the previous patch.
>
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> Suggested-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Antonio Argenziano <antonio.argenziano at intel.com>
> ---
> Note that the 'wait' subtest is mysteriously hanging for me in the no-op
> batch send by gem_test_engines, but only on RCS engine. TBD while I am
> getting some CI results.
> ---
> lib.tar | Bin 0 -> 102400 bytes
> tests/gem_eio.c | 97 ++++++++++++++++++++++++++++++++++++++++----------------
> 2 files changed, 70 insertions(+), 27 deletions(-)
> create mode 100644 lib.tar
>
> diff --git a/lib.tar b/lib.tar
> new file mode 100644
> index 0000000000000000000000000000000000000000..ea04fad219a87f2e975852989526f8da4c9b7d6d
> GIT binary patch
> literal 102400
> zcmeHw>vkJQlBWMsPf=!{kwJ=gUAkMAJc3A2!kPrQASAWM<5LF&3M57#fW}3X+V;H9
Looks correct.
> diff --git a/tests/gem_eio.c b/tests/gem_eio.c
> index 4bcc5937db39..93400056124b 100644
> --- a/tests/gem_eio.c
> +++ b/tests/gem_eio.c
> @@ -71,26 +71,23 @@ static void trigger_reset(int fd)
> gem_quiescent_gpu(fd);
> }
>
> -static void wedge_gpu(int fd)
> +static void manual_hang(int drm_fd)
> {
> - /* First idle the GPU then disable GPU resets before injecting a hang */
> - gem_quiescent_gpu(fd);
> -
> - igt_require(i915_reset_control(false));
> + int dir = igt_debugfs_dir(drm_fd);
>
> - igt_debug("Wedging GPU by injecting hang\n");
> - igt_post_hang_ring(fd, igt_hang_ring(fd, I915_EXEC_DEFAULT));
> + igt_sysfs_set(dir, "i915_wedged", "-1");
>
> - igt_assert(i915_reset_control(true));
> + close(dir);
> }
Ok.
> -static void wedgeme(int drm_fd)
> +static void wedge_gpu(int fd)
> {
> - int dir = igt_debugfs_dir(drm_fd);
> -
> - igt_sysfs_set(dir, "i915_wedged", "-1");
> + /* First idle the GPU then disable GPU resets before injecting a hang */
> + gem_quiescent_gpu(fd);
>
> - close(dir);
> + igt_require(i915_reset_control(false));
> + manual_hang(fd);
> + igt_assert(i915_reset_control(true));
> }
Ok.
>
> static int __gem_throttle(int fd)
> @@ -149,29 +146,66 @@ static int __gem_wait(int fd, uint32_t handle, int64_t timeout)
> return err;
> }
>
> +static igt_spin_t * __spin_poll(int fd, uint32_t ctx, unsigned long flags)
> +{
> + if (gem_can_store_dword(fd, flags))
> + return __igt_spin_batch_new_poll(fd, ctx, flags);
> + else
> + return __igt_spin_batch_new(fd, ctx, flags, 0);
> +}
> +
> +static void __spin_wait(int fd, igt_spin_t *spin)
> +{
> + if (spin->running) {
> + while (!*((volatile bool *)spin->running))
> + ;
> + } else {
> + igt_debug("__spin_wait - usleep mode\n");
> + usleep(500e3); /* Better than nothing! */
> + }
> +}
> +
> +/*
> + * Wedge the GPU when we know our batch is running.
> + */
> +static void wedge_after_running(int fd, igt_spin_t *spin)
> +{
> + __spin_wait(fd, spin);
> + manual_hang(fd);
> +}
> +
> static void test_wait(int fd)
> {
> - igt_hang_t hang;
> + struct timespec ts = { };
> + igt_spin_t *hang;
>
> igt_require_gem(fd);
>
> + igt_nsec_elapsed(&ts);
> +
> /* If the request we wait on completes due to a hang (even for
> * that request), the user expects the return value to 0 (success).
> */
> - hang = igt_hang_ring(fd, I915_EXEC_DEFAULT);
> - igt_assert_eq(__gem_wait(fd, hang.handle, -1), 0);
> - igt_post_hang_ring(fd, hang);
> + igt_require(i915_reset_control(true));
> + hang = __spin_poll(fd, 0, I915_EXEC_DEFAULT);
> + wedge_after_running(fd, hang);
> + igt_assert_eq(__gem_wait(fd, hang->handle, -1), 0);
> + igt_spin_batch_free(fd, hang);
>
> /* If the GPU is wedged during the wait, again we expect the return
> * value to be 0 (success).
> */
> igt_require(i915_reset_control(false));
> - hang = igt_hang_ring(fd, I915_EXEC_DEFAULT);
> - igt_assert_eq(__gem_wait(fd, hang.handle, -1), 0);
> - igt_post_hang_ring(fd, hang);
> + hang = __spin_poll(fd, 0, I915_EXEC_DEFAULT);
> + wedge_after_running(fd, hang);
> + igt_assert_eq(__gem_wait(fd, hang->handle, -1), 0);
> + igt_spin_batch_free(fd, hang);
> igt_require(i915_reset_control(true));
Hmm. These are not equivalent to the original test. The tests
requires hangcheck to kick in while the test is blocked on igt_wait.
To do a fast equivalent, we need to kick off a timer. (Here we are just
asking if a wait on an already completed request doesn't block, not how
we handle the reset in the middle of a wait. Seems a reasonable addition
though.)
I think that's a general pattern worth repeating for the rest of tests:
don't immediately inject the hang, but leave it a few milliseconds to
allow us to block on the subsequent wait. I would even repeat the tests
a few times with different timeouts; 0, 1us, 10ms (thinking of the
different phases for i915_request_wait).
> trigger_reset(fd);
> +
> + /* HACK for CI */
> + igt_assert(igt_nsec_elapsed(&ts) < 5e9);
igt_seconds_elapsed() the approximation is worth the readability.
In this case you might like to try igt_set_timeout(), as I think each
subtest and exithandlers are in place to make them robust against
premature failures.
-Chris
More information about the igt-dev
mailing list