[Intel-gfx] [PATCH igt] igt: Repalce drv_missed_irq_hang script with a C-equivalent
Chris Wilson
chris at chris-wilson.co.uk
Fri Jun 17 14:41:22 UTC 2016
In order to control some of the finer detail of detecting when we missed
an interrupt, replace the shell script with C.
This version submits a hanging batch and uses a child process to unhang
it, whilst the parent sleeps. As the child process is prevented from
running whilst the parent is alive (as the child is a low priority
normal process whereas the parent is a RT process), the child can only
unhang the parent after i915_wait_request() has spun up and tried to
enable the interrupt. In contrast, the shell script guessed a workload
that should take long enough for the i915_spin_request() to miss the
completion, but that was not guaranteed.
A minor convenience of the C version is that we don't have to worry
about install paths to find the binaries underneath.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
tests/Makefile.sources | 1 +
tests/drv_missed_irq.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++
tests/drv_missed_irq_hang | 80 ----------------------
3 files changed, 171 insertions(+), 80 deletions(-)
create mode 100644 tests/drv_missed_irq.c
delete mode 100755 tests/drv_missed_irq_hang
diff --git a/tests/Makefile.sources b/tests/Makefile.sources
index 941568d..d74a93f 100644
--- a/tests/Makefile.sources
+++ b/tests/Makefile.sources
@@ -142,6 +142,7 @@ TESTS_progs = \
drm_vma_limiter_cached \
drm_vma_limiter_cpu \
drm_vma_limiter_gtt \
+ drv_missed_irq \
gem_bad_length \
gem_cpu_reloc \
gem_cs_prefetch \
diff --git a/tests/drv_missed_irq.c b/tests/drv_missed_irq.c
new file mode 100644
index 0000000..0b1cfb8
--- /dev/null
+++ b/tests/drv_missed_irq.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <sched.h>
+
+#include "igt.h"
+#include "igt_stats.h"
+
+IGT_TEST_DESCRIPTION("Inject missed interrupts and make sure they are caught");
+
+static void trigger_missed_interrupt(int fd, unsigned ring)
+{
+ const int gen = intel_gen(intel_get_drm_devid(fd));
+ struct drm_i915_gem_exec_object2 obj;
+ struct drm_i915_gem_relocation_entry reloc;
+ struct drm_i915_gem_execbuffer2 execbuf;
+ uint32_t *batch;
+ int i;
+
+ memset(&obj, 0, sizeof(obj));
+ obj.handle = gem_create(fd, 4096);
+ obj.relocs_ptr = (uintptr_t)&reloc;
+ obj.relocation_count = 1;
+
+ memset(&reloc, 0, sizeof(reloc));
+ reloc.target_handle = obj.handle; /* recurse */
+ reloc.presumed_offset = 0;
+ reloc.offset = sizeof(uint32_t);
+ reloc.delta = 0;
+ reloc.read_domains = I915_GEM_DOMAIN_COMMAND;
+ reloc.write_domain = 0;
+
+ batch = gem_mmap__wc(fd, obj.handle, 0, 4096, PROT_WRITE);
+ gem_set_domain(fd, obj.handle,
+ I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+ i = 0;
+ batch[i] = MI_BATCH_BUFFER_START;
+ if (gen >= 8) {
+ batch[i] |= 1 << 8 | 1;
+ batch[++i] = 0;
+ batch[++i] = 0;
+ } else if (gen >= 6) {
+ batch[i] |= 1 << 8;
+ batch[++i] = 0;
+ } else {
+ batch[i] |= 2 << 6;
+ batch[++i] = 0;
+ if (gen < 4) {
+ batch[i] |= 1;
+ reloc.delta = 1;
+ }
+ }
+
+ memset(&execbuf, 0, sizeof(execbuf));
+ execbuf.buffers_ptr = (uintptr_t)&obj;
+ execbuf.buffer_count = 1;
+ execbuf.flags = ring;
+
+ execbuf.flags = ring;
+ if (__gem_execbuf(fd, &execbuf))
+ goto out;
+
+ igt_fork(child, 1) {
+ /* We are now a low priority child on the *same* CPU as the
+ * parent. We will have to wait for our parent to sleep
+ * (gem_sync -> i915_wait_request) before we run.
+ */
+ *batch = MI_BATCH_BUFFER_END;
+ __sync_synchronize();
+ }
+
+ gem_sync(fd, obj.handle);
+ igt_waitchildren();
+
+out:
+ gem_close(fd, obj.handle);
+ munmap(batch, 4096);
+}
+
+static void bind_to_cpu(int cpu)
+{
+ const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+ struct sched_param rt = {.sched_priority = 99 };
+ cpu_set_t allowed;
+
+ igt_assert(sched_setscheduler(getpid(), SCHED_RR | SCHED_RESET_ON_FORK, &rt) == 0);
+
+ CPU_ZERO(&allowed);
+ CPU_SET(cpu % ncpus, &allowed);
+ igt_assert(sched_setaffinity(getpid(), sizeof(cpu_set_t), &allowed) == 0);
+}
+
+igt_simple_main
+{
+ const struct intel_execution_engine *e;
+ FILE *file;
+ unsigned expect_rings;
+ unsigned missed_rings;
+ int fd;
+
+ igt_skip_on_simulation();
+
+ fd = drm_open_driver(DRIVER_INTEL);
+ gem_require_mmap_wc(fd);
+
+ file = igt_debugfs_fopen("i915_ring_test_irq", "w");
+ fprintf(file, "0x%x", -1);
+ fclose(file);
+
+ file = igt_debugfs_fopen("i915_ring_test_irq", "r");
+ fscanf(file, "%x", &expect_rings);
+ fclose(file);
+
+ igt_debug("Testing rings %x\n", expect_rings);
+
+ igt_fork_hang_detector(fd);
+ intel_detect_and_clear_missed_interrupts(fd);
+
+ bind_to_cpu(0);
+ for (e = intel_execution_engines; e->name; e++) {
+ if (expect_rings == -1 && e->exec_id)
+ continue;
+
+ if (expect_rings != -1 && e->exec_id == 0)
+ continue;
+
+ igt_debug("Executing on ring %s [%x]\n",
+ e->name, e->exec_id | e->flags);
+
+ trigger_missed_interrupt(fd, e->exec_id | e->flags);
+ }
+
+ missed_rings = intel_detect_and_clear_missed_interrupts(fd);
+ igt_stop_hang_detector();
+
+ file = igt_debugfs_fopen("i915_ring_test_irq", "w");
+ fprintf(file, "%x", 0);
+ fclose(file);
+
+ if (expect_rings == -1) {
+ igt_assert_eq_u32(missed_rings, 1);
+ } else {
+ igt_assert_eq_u32(missed_rings, expect_rings);
+ }
+
+ close(fd);
+}
diff --git a/tests/drv_missed_irq_hang b/tests/drv_missed_irq_hang
deleted file mode 100755
index e76c7db..0000000
--- a/tests/drv_missed_irq_hang
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/bin/bash
-#
-# Testcase: Simulate missed breadcrumb interrupts
-#
-
-SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
-. $SOURCE_DIR/drm_lib.sh
-
-oldpath=`pwd`
-
-cd $i915_dfs_path
-
-function blt_wait {
- $oldpath/$SOURCE_DIR/../benchmarks/gem_blt -r 1 -b 64 -t 1 -S > /dev/null
-}
-
-function check_for_missed_irq {
- test `cat i915_ring_missed_irq` != 0x00000000
-}
-
-function check_for_hang {
- if cat i915_error_state | grep -v "no error state collected" > /dev/null ; then
- echo "gpu hang reported"
- exit $IGT_EXIT_FAILURE
- fi
-}
-
-if [ ! -f i915_ring_missed_irq ] ; then
- echo "kernel doesn't support interrupt masking"
- exit $IGT_EXIT_SKIP
-fi
-
-# clear error state first
-echo > i915_error_state
-blt_wait
-if check_for_missed_irq; then
- echo "missed interrupts detected before starting test"
- exit $IGT_EXIT_SKOP
-fi
-check_for_hang
-
-echo 0xf > i915_ring_test_irq
-echo "Interrupts masked"
-if test `cat i915_ring_test_irq` != 0x0000000f; then
- echo "Failed to set interrupt mask"
- exit $IGT_EXIT_FAILURE
-fi
-
-blt_wait
-if ! check_for_missed_irq; then
- echo "missed interrupts undetected"
- exit $IGT_EXIT_FAILURE
-fi
-check_for_hang
-
-echo 0 > i915_ring_test_irq
-echo "Interrupts unmasked"
-if test `cat i915_ring_test_irq` != 0x00000000; then
- echo "Failed to clear interrupt mask"
- exit $IGT_EXIT_FAILURE
-fi
-
-blt_wait
-check_for_hang
-
-echo 0 > i915_ring_missed_irq
-echo "Cleared missed interrupts"
-if test `cat i915_ring_missed_irq` != 0x00000000; then
- echo "Failed to clear missed interrupts"
- exit $IGT_EXIT_FAILURE
-fi
-
-blt_wait
-if check_for_missed_irq; then
- echo "missed interrupts detected afterwards"
- exit $IGT_EXIT_FAILURE
-fi
-check_for_hang
-
-exit $IGT_EXIT_SUCCESS
--
2.8.1
More information about the Intel-gfx
mailing list