All of lore.kernel.org
 help / color / mirror / Atom feed
* i-g-t dummyload/spin batch v10
@ 2016-11-23 10:59 Abdiel Janulgue
  2016-11-23 10:59 ` [i-g-t PATCH v10 1/5] lib: Make signal helper definitions reusable Abdiel Janulgue
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-23 10:59 UTC (permalink / raw)
  To: intel-gfx

Mostly reviewed by Tomeu but includes last minute changes
from Chris: split out the timeout function and api naming
clarifications.

- Abdiel

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v10 1/5] lib: Make signal helper definitions reusable
  2016-11-23 10:59 i-g-t dummyload/spin batch v10 Abdiel Janulgue
@ 2016-11-23 10:59 ` Abdiel Janulgue
  2016-11-23 10:59 ` [i-g-t PATCH v10 2/5] lib: add igt_dummyload Abdiel Janulgue
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-23 10:59 UTC (permalink / raw)
  To: intel-gfx

Lots of test cases are re-declaring this.

v2: Remove definition in benchmarks/gem_syslatency.c

Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 benchmarks/gem_syslatency.c |  4 ----
 lib/igt_aux.c               | 11 -----------
 lib/igt_aux.h               | 10 ++++++++++
 lib/igt_core.c              |  3 ---
 tests/drv_hangman.c         |  1 -
 5 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/benchmarks/gem_syslatency.c b/benchmarks/gem_syslatency.c
index 6cad3a0..83bfac7 100644
--- a/benchmarks/gem_syslatency.c
+++ b/benchmarks/gem_syslatency.c
@@ -133,10 +133,6 @@ static void *gem_busyspin(void *arg)
 	return NULL;
 }
 
-#define MSEC_PER_SEC (1000)
-#define USEC_PER_SEC (1000 * MSEC_PER_SEC)
-#define NSEC_PER_SEC (1000 * USEC_PER_SEC)
-
 static double elapsed(const struct timespec *a, const struct timespec *b)
 {
 	return 1e9*(b->tv_sec - a->tv_sec) + (b->tv_nsec - a ->tv_nsec);
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index 421f6d4..b5ae854 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -75,17 +75,6 @@
  * fit into any other topic.
  */
 
-
-/* signal interrupt helpers */
-
-#define MSEC_PER_SEC (1000)
-#define USEC_PER_SEC (1000*MSEC_PER_SEC)
-#define NSEC_PER_SEC (1000*USEC_PER_SEC)
-
-/* signal interrupt helpers */
-#define gettid() syscall(__NR_gettid)
-#define sigev_notify_thread_id _sigev_un._tid
-
 static struct __igt_sigiter_global {
 	pid_t tid;
 	timer_t timer;
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index d30196b..d4da499 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -35,6 +35,16 @@
 extern drm_intel_bo **trash_bos;
 extern int num_trash_bos;
 
+/* signal interrupt helpers */
+
+#define MSEC_PER_SEC (1000)
+#define USEC_PER_SEC (1000*MSEC_PER_SEC)
+#define NSEC_PER_SEC (1000*USEC_PER_SEC)
+
+/* signal interrupt helpers */
+#define gettid() syscall(__NR_gettid)
+#define sigev_notify_thread_id _sigev_un._tid
+
 /* auxialiary igt helpers from igt_aux.c */
 /* generally useful helpers */
 void igt_fork_signal_helper(void);
diff --git a/lib/igt_core.c b/lib/igt_core.c
index 9cd5f98..f64c809 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -398,9 +398,6 @@ error:
 	return -errno;
 }
 
-#define MSEC_PER_SEC (1000)
-#define USEC_PER_SEC (1000*MSEC_PER_SEC)
-#define NSEC_PER_SEC (1000*USEC_PER_SEC)
 uint64_t igt_nsec_elapsed(struct timespec *start)
 {
 	struct timespec now;
diff --git a/tests/drv_hangman.c b/tests/drv_hangman.c
index f80d65d..db0a077 100644
--- a/tests/drv_hangman.c
+++ b/tests/drv_hangman.c
@@ -293,7 +293,6 @@ static void test_error_state_capture(unsigned ring_id,
  * case and it takes a lot more time to wrap, so the acthd can potentially keep
  * increasing for a long time
  */
-#define NSEC_PER_SEC	1000000000LL
 static void hangcheck_unterminated(void)
 {
 	int fd;
-- 
2.9.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v10 2/5] lib: add igt_dummyload
  2016-11-23 10:59 i-g-t dummyload/spin batch v10 Abdiel Janulgue
  2016-11-23 10:59 ` [i-g-t PATCH v10 1/5] lib: Make signal helper definitions reusable Abdiel Janulgue
@ 2016-11-23 10:59 ` Abdiel Janulgue
  2016-11-23 11:47   ` Chris Wilson
  2016-11-23 10:59 ` [i-g-t PATCH v10 3/5] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-23 10:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

A lot of igt testcases need some GPU workload to make sure a race
window is big enough. Unfortunately having a fixed amount of
workload leads to spurious test failures or overly long runtimes
on some fast/slow platforms. This library contains functionality
to submit GPU workloads that should consume exactly a specific
amount of time.

v2 : Add recursive batch feature from Chris
v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch
     by adding a dummy reloc to the bo as suggested by Ville.
v4:  Fix dependency reloc as write instead of read (Ville).
     Fix wrong handling of batchbuffer start on ILK causing
     test failure
v5:  Convert kms_busy to use this api
v6:  Add this library to docs
v7:  Document global use of batch, reuse defines
     Minor code cleanups.
     Rename igt_spin_batch and igt_post_spin_batch to
     igt_spin_batch_new and igt_spin_batch_free
     respectively (Tomeu Vizoso).
     Fix error in dependency relocation handling in HSW causing
     tests to fail.
v8:  Restore correct order of objects in the execbuffer. Batch
     object should always be last.
v9 : Add helper to terminate batch manually
v10: Split timeout function. Clarify function names (Chris)

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: tomeu@tomeuvizoso.net
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/igt.h                                          |   1 +
 lib/igt_dummyload.c                                | 299 +++++++++++++++++++++
 lib/igt_dummyload.h                                |  47 ++++
 5 files changed, 350 insertions(+)
 create mode 100644 lib/igt_dummyload.c
 create mode 100644 lib/igt_dummyload.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c862f2a..55902ab 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -32,6 +32,7 @@
     <xi:include href="xml/intel_io.xml"/>
     <xi:include href="xml/igt_vc4.xml"/>
     <xi:include href="xml/igt_vgem.xml"/>
+    <xi:include href="xml/igt_dummyload.xml"/>
   </chapter>
   <xi:include href="xml/igt_test_programs.xml"/>
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e8e277b..7fc5ec2 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -75,6 +75,8 @@ lib_source_list =	 	\
 	igt_draw.h		\
 	igt_pm.c		\
 	igt_pm.h		\
+	igt_dummyload.c		\
+	igt_dummyload.h		\
 	uwildmat/uwildmat.h	\
 	uwildmat/uwildmat.c	\
 	$(NULL)
diff --git a/lib/igt.h b/lib/igt.h
index d751f24..a0028d5 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -32,6 +32,7 @@
 #include "igt_core.h"
 #include "igt_debugfs.h"
 #include "igt_draw.h"
+#include "igt_dummyload.h"
 #include "igt_fb.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
new file mode 100644
index 0000000..afb0851
--- /dev/null
+++ b/lib/igt_dummyload.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "igt.h"
+#include "igt_dummyload.h"
+#include <time.h>
+#include <signal.h>
+#include <sys/syscall.h>
+
+/**
+ * SECTION:igt_dummyload
+ * @short_description: Library for submitting GPU workloads
+ * @title: Dummyload
+ * @include: igt.h
+ *
+ * A lot of igt testcases need some GPU workload to make sure a race window is
+ * big enough. Unfortunately having a fixed amount of workload leads to
+ * spurious test failures or overly long runtimes on some fast/slow platforms.
+ * This library contains functionality to submit GPU workloads that should
+ * consume exactly a specific amount of time.
+ */
+
+#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
+#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
+
+#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
+
+static const int bo_size = 4096;
+
+static void
+fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
+	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
+{
+	memset(obj, 0, sizeof(*obj));
+	obj->handle = gem_handle;
+	obj->relocation_count = count;
+	obj->relocs_ptr = (uintptr_t)relocs;
+}
+
+static void
+fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+	   uint32_t gem_handle, uint32_t offset,
+	   uint32_t read_domains, uint32_t write_domains)
+{
+	reloc->target_handle = gem_handle;
+	reloc->delta = 0;
+	reloc->offset = offset * sizeof(uint32_t);
+	reloc->presumed_offset = 0;
+	reloc->read_domains = read_domains;
+	reloc->write_domain = write_domains;
+}
+
+/*
+ * Needs to be global. Signal handlers don't accept arguments
+ */
+static uint32_t *batch;
+
+static uint32_t emit_recursive_batch(int fd, int engine, unsigned dep_handle)
+{
+	const int gen = intel_gen(intel_get_drm_devid(fd));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry relocs[2];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	unsigned engines[16];
+	unsigned nengine, handle;
+	int i = 0, reloc_count = 0, buf_count = 0;
+
+	buf_count = 0;
+	nengine = 0;
+	if (engine < 0) {
+		for_each_engine(fd, engine)
+			if (engine)
+				engines[nengine++] = engine;
+	} else {
+		gem_require_ring(fd, engine);
+		engines[nengine++] = engine;
+	}
+	igt_require(nengine);
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	memset(obj, 0, sizeof(obj));
+	memset(relocs, 0, sizeof(relocs));
+
+	execbuf.buffers_ptr = (uintptr_t) obj;
+	handle = gem_create(fd, bo_size);
+	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
+	igt_assert(batch);
+	gem_set_domain(fd, handle,
+			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+	if (dep_handle > 0) {
+		igt_assert(nengine == 1);
+		/* dummy write to dependency */
+		fill_object(&obj[buf_count], dep_handle, NULL, 0);
+		buf_count++;
+
+		fill_reloc(&relocs[reloc_count], dep_handle, 256,
+			   I915_GEM_DOMAIN_RENDER,
+			   I915_GEM_DOMAIN_RENDER);
+		reloc_count++;
+	}
+
+	if (gen >= 8) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		batch[i++] = 0;
+	} else if (gen >= 6) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+	} else {
+		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
+			((gen < 4) ? 1 : 0);
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		if (gen < 4)
+			relocs[reloc_count].delta = 1;
+	}
+	reloc_count++;
+
+	fill_object(&obj[buf_count], handle, relocs, reloc_count);
+	buf_count++;
+
+	for (i = 0; i < nengine; i++) {
+		execbuf.flags &= ~ENGINE_MASK;
+		execbuf.flags = engines[i];
+		execbuf.buffer_count = buf_count;
+		gem_execbuf(fd, &execbuf);
+	}
+
+	return handle;
+}
+
+static void exit_batch_handler(int sig, siginfo_t *info, void *spin)
+{
+	*batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+/**
+ * igt_spin_batch_new:
+ * @fd: open i915 drm file descriptor
+ * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
+ *          than 0, execute on all available rings.
+ * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
+ *              relocation entry to this buffer within the batch.
+ *
+ * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
+ * contains the batch's handle that can be waited upon. The returned structure
+ * must be passed to igt_spin_batch_free() for post-processing.
+ *
+ * Returns:
+ * Structure with helper internal state for igt_spin_batch_free().
+ */
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned dep_handle)
+{
+	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
+	uint32_t handle = emit_recursive_batch(fd, engine, dep_handle);
+	int64_t wait_timeout = 0;
+	igt_assert_eq(gem_wait(fd, handle, &wait_timeout), -ETIME);
+
+	spin->handle = handle;
+	spin->batch = batch;
+	spin->timer = NULL;
+
+	return spin;
+}
+
+/**
+ * igt_spin_batch_set_timeout:
+ * @spin: spin batch state from igt_spin_batch_new()
+ * @ns: amount of time in nanoseconds the batch continues to execute
+ *      before finishing.
+ *
+ * Specify a timeout. This ends the recursive batch associated with @spin after
+ * the timeout has elapsed.
+ */
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
+{
+	timer_t timer;
+	struct sigevent sev;
+	struct sigaction act;
+	struct itimerspec its;
+
+	igt_assert(ns > 0);
+	if (!spin)
+		return;
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+	sev.sigev_notify_thread_id = gettid();
+	sev.sigev_signo = SIGRTMIN + 1;
+	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
+	igt_assert(timer > 0);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = exit_batch_handler;
+	act.sa_flags = SA_SIGINFO;
+	igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0);
+
+	memset(&its, 0, sizeof(its));
+	its.it_value.tv_sec = ns / NSEC_PER_SEC;
+	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
+	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
+
+	spin->timer = timer;
+}
+
+/**
+ * igt_spin_batch_end:
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * End the recursive batch associated with @spin manually.
+ */
+void igt_spin_batch_end(igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	if (spin->handle > 0)
+		exit_batch_handler(0, NULL, NULL);
+}
+
+/**
+ * igt_spin_batch_free:
+ * @fd: open i915 drm file descriptor
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * This function does the necessary post-processing after starting a recursive
+ * batch with igt_spin_batch_new().
+ */
+void igt_spin_batch_free(int fd, igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	if (spin->handle > 0)
+		gem_close(fd, spin->handle);
+
+	if (spin->timer > 0)
+		timer_delete(spin->timer);
+
+	munmap(spin->batch, bo_size);
+	free(spin);
+}
+
+/**
+ * igt_spin_batch_wait:
+ * @fd: open i915 drm file descriptor
+ * @ns: amount of time in nanoseconds the batch continues to execute
+ *      before finishing.
+ * @engine: ring to execute batch OR'd with execbuf flags. If value is less
+ *          than 0, execute on all available rings.
+ * @dep_handle: handle to a buffer object dependency. If greater than 0, include
+ *              this buffer on the wait dependency
+ *
+ * Convenience function similar to igt_spin_batch_new() then setting the timeout
+ * with igt_spin_batch_set_timeout(), but waits on the recursive batch to finish
+ * instead of returning right away. The function also does the necessary
+ * post-processing automatically.
+ */
+void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle)
+{
+	igt_spin_t *spin = igt_spin_batch_new(fd, engine, dep_handle);
+	int64_t wait_timeout = ns + (0.5 * NSEC_PER_SEC);
+	igt_spin_batch_set_timeout(spin, wait_timeout);
+	igt_assert_eq(gem_wait(fd, spin->handle, &wait_timeout), 0);
+
+	igt_spin_batch_free(fd, spin);
+}
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
new file mode 100644
index 0000000..68dc0d9
--- /dev/null
+++ b/lib/igt_dummyload.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#ifndef __IGT_DUMMYLOAD_H__
+#define __IGT_DUMMYLOAD_H__
+
+typedef struct igt_spin {
+	unsigned handle;
+	uint32_t *batch;
+	timer_t timer;
+} igt_spin_t;
+
+
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned dep_handle);
+
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns);
+
+void igt_spin_batch_end(igt_spin_t *spin);
+
+void igt_spin_batch_free(int fd, igt_spin_t *spin);
+
+void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle);
+
+
+#endif /* __IGT_DUMMYLOAD_H__ */
-- 
2.9.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v10 3/5] igt/gem_wait: Use new igt_spin_batch
  2016-11-23 10:59 i-g-t dummyload/spin batch v10 Abdiel Janulgue
  2016-11-23 10:59 ` [i-g-t PATCH v10 1/5] lib: Make signal helper definitions reusable Abdiel Janulgue
  2016-11-23 10:59 ` [i-g-t PATCH v10 2/5] lib: add igt_dummyload Abdiel Janulgue
@ 2016-11-23 10:59 ` Abdiel Janulgue
  2016-11-23 10:59 ` [i-g-t PATCH v10 4/5] igt/kms_flip: " Abdiel Janulgue
  2016-11-23 10:59 ` [i-g-t PATCH v10 5/5] igt/kms_busy.c: " Abdiel Janulgue
  4 siblings, 0 replies; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-23 10:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

v7: Adapt to api rename
v8: Restore sanitycheck wait on the recursive batch and
    avoid using C99 locals (Chris Wilson)
v9: Explicitly quit the batch instead of timing out right away
v10: Adapt to api rename

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 tests/gem_wait.c | 124 +++----------------------------------------------------
 1 file changed, 6 insertions(+), 118 deletions(-)

diff --git a/tests/gem_wait.c b/tests/gem_wait.c
index b4127de..ebcaec2 100644
--- a/tests/gem_wait.c
+++ b/tests/gem_wait.c
@@ -27,18 +27,6 @@
 
 #include "igt.h"
 
-#include <signal.h>
-#include <time.h>
-#include <sys/syscall.h>
-
-#define gettid() syscall(__NR_gettid)
-#define sigev_notify_thread_id _sigev_un._tid
-
-#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
-#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
-
-#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
-
 static int __gem_wait(int fd, struct drm_i915_gem_wait *w)
 {
 	int err;
@@ -75,98 +63,24 @@ static void invalid_buf(int fd)
 	igt_assert_eq(__gem_wait(fd, &wait), -ENOENT);
 }
 
-static uint32_t *batch;
-
-static void sigiter(int sig, siginfo_t *info, void *arg)
-{
-	*batch = MI_BATCH_BUFFER_END;
-	__sync_synchronize();
-}
-
-#define MSEC_PER_SEC (1000)
-#define USEC_PER_SEC (1000 * MSEC_PER_SEC)
-#define NSEC_PER_SEC (1000 * USEC_PER_SEC)
-
 #define BUSY 1
 #define HANG 2
 static void basic(int fd, unsigned engine, unsigned flags)
 {
-	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;
 	struct drm_i915_gem_wait wait;
-	unsigned engines[16];
-	unsigned nengine;
-	int i, timeout;
-
-	nengine = 0;
-	if (engine == -1) {
-		for_each_engine(fd, engine)
-			if (engine) engines[nengine++] = engine;
-	} else {
-		igt_require(gem_has_ring(fd, engine));
-		engines[nengine++] = engine;
-	}
-	igt_require(nengine);
-
-	memset(&execbuf, 0, sizeof(execbuf));
-	execbuf.buffers_ptr = (uintptr_t)&obj;
-	execbuf.buffer_count = 1;
-
-	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));
-
-	batch = gem_mmap__gtt(fd, obj.handle, 4096, PROT_WRITE);
-	gem_set_domain(fd, obj.handle,
-			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
-
-	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;
-
-	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;
-		}
-	}
-
-	for (i = 0; i < nengine; i++) {
-		execbuf.flags &= ~ENGINE_MASK;
-		execbuf.flags |= engines[i];
-		gem_execbuf(fd, &execbuf);
-	}
+	igt_spin_t *spin = igt_spin_batch_new(fd, engine, NULL);
 
 	memset(&wait, 0, sizeof(wait));
-	wait.bo_handle = obj.handle;
+	wait.bo_handle = spin->handle;
 	igt_assert_eq(__gem_wait(fd, &wait), -ETIME);
 
 	if (flags & BUSY) {
+		int timeout;
 		struct timespec tv;
 
 		timeout = 120;
 		if ((flags & HANG) == 0) {
-			*batch = MI_BATCH_BUFFER_END;
-			__sync_synchronize();
+			igt_spin_batch_end(spin);
 			timeout = 1;
 		}
 
@@ -174,29 +88,7 @@ static void basic(int fd, unsigned engine, unsigned flags)
 		while (__gem_wait(fd, &wait) == -ETIME)
 			igt_assert(igt_seconds_elapsed(&tv) < timeout);
 	} else {
-		timer_t timer;
-
-		if ((flags & HANG) == 0) {
-			struct sigevent sev;
-			struct sigaction act;
-			struct itimerspec its;
-
-			memset(&sev, 0, sizeof(sev));
-			sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
-			sev.sigev_notify_thread_id = gettid();
-			sev.sigev_signo = SIGRTMIN + 1;
-			igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
-
-			memset(&act, 0, sizeof(act));
-			act.sa_sigaction = sigiter;
-			act.sa_flags = SA_SIGINFO;
-			igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0);
-
-			memset(&its, 0, sizeof(its));
-			its.it_value.tv_nsec = 0;
-			its.it_value.tv_sec = 1;
-			igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
-		}
+		igt_spin_batch_set_timeout(spin, NSEC_PER_SEC);
 
 		wait.timeout_ns = NSEC_PER_SEC / 2; /* 0.5s */
 		igt_assert_eq(__gem_wait(fd, &wait), -ETIME);
@@ -215,13 +107,9 @@ static void basic(int fd, unsigned engine, unsigned flags)
 		wait.timeout_ns = 0;
 		igt_assert_eq(__gem_wait(fd, &wait), 0);
 		igt_assert(wait.timeout_ns == 0);
-
-		if ((flags & HANG) == 0)
-			timer_delete(timer);
 	}
 
-	gem_close(fd, obj.handle);
-	munmap(batch, 4096);
+	igt_spin_batch_free(fd, spin);
 }
 
 igt_main
-- 
2.9.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v10 4/5] igt/kms_flip: Use new igt_spin_batch
  2016-11-23 10:59 i-g-t dummyload/spin batch v10 Abdiel Janulgue
                   ` (2 preceding siblings ...)
  2016-11-23 10:59 ` [i-g-t PATCH v10 3/5] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue
@ 2016-11-23 10:59 ` Abdiel Janulgue
  2016-11-23 11:35   ` Chris Wilson
  2016-11-23 10:59 ` [i-g-t PATCH v10 5/5] igt/kms_busy.c: " Abdiel Janulgue
  4 siblings, 1 reply; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-23 10:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

v7: Reuse NSEC_PER_SEC defines
v8: Don't wait on the fb, it must be busy. Exit the spin batch
    when flip is queued (Chris Wilson)
v10: Adapt to api rename

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 tests/kms_flip.c | 212 +++++++------------------------------------------------
 1 file changed, 26 insertions(+), 186 deletions(-)

diff --git a/tests/kms_flip.c b/tests/kms_flip.c
index 2a9fe2e..289335a 100644
--- a/tests/kms_flip.c
+++ b/tests/kms_flip.c
@@ -85,9 +85,6 @@
 #define DRM_CAP_TIMESTAMP_MONOTONIC 6
 #endif
 
-#define USEC_PER_SEC 1000000L
-#define NSEC_PER_SEC 1000000000L
-
 drmModeRes *resources;
 int drm_fd;
 static drm_intel_bufmgr *bufmgr;
@@ -191,109 +188,6 @@ static unsigned long gettime_us(void)
 	return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
 }
 
-static int calibrate_dummy_load(struct test_output *o,
-				const char *ring_name,
-				int (*emit)(struct test_output *o, int limit, int timeout))
-{
-	unsigned long start;
-	int ops = 1;
-
-	start = gettime_us();
-
-	do {
-		unsigned long diff;
-		int ret;
-
-		ret = emit(o, (ops+1)/2, 10);
-		diff = gettime_us() - start;
-
-		if (ret || diff / USEC_PER_SEC >= 1)
-			break;
-
-		ops += ops;
-	} while (ops < 100000);
-
-	igt_debug("%s dummy load calibrated: %d operations / second\n",
-		  ring_name, ops);
-
-	return ops;
-}
-
-static void blit_copy(drm_intel_bo *dst, drm_intel_bo *src,
-		      unsigned int width, unsigned int height,
-		      unsigned int dst_pitch, unsigned int src_pitch)
-{
-	BLIT_COPY_BATCH_START(0);
-	OUT_BATCH((3 << 24) | /* 32 bits */
-		  (0xcc << 16) | /* copy ROP */
-		  dst_pitch);
-	OUT_BATCH(0 << 16 | 0);
-	OUT_BATCH(height << 16 | width);
-	OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
-	OUT_BATCH(0 << 16 | 0);
-	OUT_BATCH(src_pitch);
-	OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0);
-	ADVANCE_BATCH();
-
-	if (batch->gen >= 6) {
-		BEGIN_BATCH(3, 0);
-		OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
-		OUT_BATCH(0);
-		OUT_BATCH(0);
-		ADVANCE_BATCH();
-	}
-}
-
-static int _emit_dummy_load__bcs(struct test_output *o, int limit, int timeout)
-{
-	int i, ret = 0;
-	drm_intel_bo *src_bo, *dst_bo, *fb_bo;
-	struct igt_fb *fb_info = &o->fb_info[o->current_fb_id];
-
-	igt_require(bufmgr);
-
-	src_bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096);
-	igt_assert(src_bo);
-
-	dst_bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096);
-	igt_assert(dst_bo);
-
-	fb_bo = gem_handle_to_libdrm_bo(bufmgr, drm_fd, "imported", fb_info->gem_handle);
-	igt_assert(fb_bo);
-
-	for (i = 0; i < limit; i++) {
-		blit_copy(dst_bo, src_bo,
-			  2048, 2048,
-			  2048*4, 2048*4);
-
-		igt_swap(src_bo, dst_bo);
-	}
-	blit_copy(fb_bo, src_bo,
-		  min(o->fb_width, 2048), min(o->fb_height, 2048),
-		  fb_info->stride, 2048*4);
-	intel_batchbuffer_flush(batch);
-
-	if (timeout > 0)
-		ret = drm_intel_gem_bo_wait(fb_bo, timeout * NSEC_PER_SEC);
-
-	drm_intel_bo_unreference(src_bo);
-	drm_intel_bo_unreference(dst_bo);
-	drm_intel_bo_unreference(fb_bo);
-
-	return ret;
-}
-
-static void emit_dummy_load__bcs(struct test_output *o, int seconds)
-{
-	static int ops_per_sec;
-
-	if (ops_per_sec == 0)
-		ops_per_sec = calibrate_dummy_load(o, "bcs",
-						   _emit_dummy_load__bcs);
-
-	_emit_dummy_load__bcs(o, seconds * ops_per_sec, 0);
-}
-
 static void emit_fence_stress(struct test_output *o)
 {
 	const int num_fences = gem_available_fences(drm_fd);
@@ -338,82 +232,6 @@ static void emit_fence_stress(struct test_output *o)
 	free(exec);
 }
 
-static int _emit_dummy_load__rcs(struct test_output *o, int limit, int timeout)
-{
-	const struct igt_fb *fb_info = &o->fb_info[o->current_fb_id];
-	igt_render_copyfunc_t copyfunc;
-	struct igt_buf sb[3], *src, *dst, *fb;
-	int i, ret = 0;
-
-	igt_require(bufmgr);
-
-	copyfunc = igt_get_render_copyfunc(devid);
-	if (copyfunc == NULL)
-		return _emit_dummy_load__bcs(o, limit, timeout);
-
-	sb[0].bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096);
-	igt_assert(sb[0].bo);
-	sb[0].size = sb[0].bo->size;
-	sb[0].tiling = I915_TILING_NONE;
-	sb[0].data = NULL;
-	sb[0].num_tiles = sb[0].bo->size;
-	sb[0].stride = 4 * 2048;
-
-	sb[1].bo = drm_intel_bo_alloc(bufmgr, "dummy_bo", 2048*2048*4, 4096);
-	igt_assert(sb[1].bo);
-	sb[1].size = sb[1].bo->size;
-	sb[1].tiling = I915_TILING_NONE;
-	sb[1].data = NULL;
-	sb[1].num_tiles = sb[1].bo->size;
-	sb[1].stride = 4 * 2048;
-
-	sb[2].bo = gem_handle_to_libdrm_bo(bufmgr, drm_fd, "imported", fb_info->gem_handle);
-	igt_assert(sb[2].bo);
-	sb[2].size = sb[2].bo->size;
-	sb[2].tiling = igt_fb_mod_to_tiling(fb_info->tiling);
-	sb[2].data = NULL;
-	sb[2].num_tiles = sb[2].bo->size;
-	sb[2].stride = fb_info->stride;
-
-	src = &sb[0];
-	dst = &sb[1];
-	fb = &sb[2];
-
-	for (i = 0; i < limit; i++) {
-		copyfunc(batch, NULL,
-			 src, 0, 0,
-			 2048, 2048,
-			 dst, 0, 0);
-
-		igt_swap(src, dst);
-	}
-	copyfunc(batch, NULL,
-		 src, 0, 0,
-		 min(o->fb_width, 2048), min(o->fb_height, 2048),
-		 fb, 0, 0);
-	intel_batchbuffer_flush(batch);
-
-	if (timeout > 0)
-		ret = drm_intel_gem_bo_wait(fb->bo, timeout * NSEC_PER_SEC);
-
-	drm_intel_bo_unreference(sb[0].bo);
-	drm_intel_bo_unreference(sb[1].bo);
-	drm_intel_bo_unreference(sb[2].bo);
-
-	return ret;
-}
-
-static void emit_dummy_load__rcs(struct test_output *o, int seconds)
-{
-	static int ops_per_sec;
-
-	if (ops_per_sec == 0)
-		ops_per_sec = calibrate_dummy_load(o, "rcs",
-						   _emit_dummy_load__rcs);
-
-	_emit_dummy_load__bcs(o, seconds * ops_per_sec, 0);
-}
-
 static void dpms_off_other_outputs(struct test_output *o)
 {
 	int i, n;
@@ -852,6 +670,8 @@ static unsigned int run_test_step(struct test_output *o)
 	struct vblank_reply vbl_reply;
 	unsigned int target_seq;
 	igt_hang_t hang;
+	igt_spin_t *spin_rcs = 0;
+	igt_spin_t *spin_bcs = 0;
 
 	target_seq = o->vblank_state.seq_step;
 	/* Absolute waits only works once we have a frame counter. */
@@ -874,10 +694,12 @@ static unsigned int run_test_step(struct test_output *o)
 		o->current_fb_id = !o->current_fb_id;
 
 	if (o->flags & TEST_WITH_DUMMY_BCS)
-		emit_dummy_load__bcs(o, 1);
+		spin_bcs = igt_spin_batch_new(drm_fd, I915_EXEC_BLT,
+					      o->fb_info[o->current_fb_id].gem_handle);
 
 	if (o->flags & TEST_WITH_DUMMY_RCS)
-		emit_dummy_load__rcs(o, 1);
+		spin_rcs = igt_spin_batch_new(drm_fd, I915_EXEC_RENDER,
+					      o->fb_info[o->current_fb_id].gem_handle);
 
 	if (o->flags & TEST_FB_RECREATE)
 		recreate_fb(o);
@@ -933,8 +755,13 @@ static unsigned int run_test_step(struct test_output *o)
 	if (o->flags & TEST_MODESET)
 		igt_assert(set_mode(o, o->fb_ids[o->current_fb_id], 0, 0) == 0);
 
-	if (o->flags & TEST_DPMS)
+	if (o->flags & TEST_DPMS) {
+		if (spin_rcs)
+			igt_spin_batch_end(spin_rcs);
+		if (spin_bcs)
+			igt_spin_batch_end(spin_bcs);
 		set_dpms(o, DRM_MODE_DPMS_ON);
+	}
 
 	if (o->flags & TEST_VBLANK_RACE) {
 		struct vblank_reply reply;
@@ -967,8 +794,13 @@ static unsigned int run_test_step(struct test_output *o)
 		igt_assert(__wait_for_vblank(TEST_VBLANK_BLOCK, o->pipe, 1, 0, &reply) == 0);
 	}
 
-	if (do_flip)
+	if (do_flip) {
 		do_or_die(do_page_flip(o, new_fb_id, !(o->flags & TEST_NOEVENT)));
+		if (spin_rcs)
+			igt_spin_batch_end(spin_rcs);
+		if (spin_bcs)
+			igt_spin_batch_end(spin_bcs);
+	}
 
 	if (o->flags & TEST_FENCE_STRESS)
 		emit_fence_stress(o);
@@ -982,7 +814,15 @@ static unsigned int run_test_step(struct test_output *o)
 				      vbl_reply.ts.tv_usec);
 			completed_events = EVENT_VBLANK;
 		}
+		if (spin_rcs)
+			igt_spin_batch_end(spin_rcs);
+		if (spin_bcs)
+			igt_spin_batch_end(spin_bcs);
 	}
+	if (spin_rcs)
+		igt_spin_batch_free(drm_fd, spin_rcs);
+	if (spin_bcs)
+		igt_spin_batch_free(drm_fd, spin_bcs);
 
 	if (do_flip && (o->flags & TEST_EBUSY))
 		igt_assert(do_page_flip(o, new_fb_id, true) == -EBUSY);
-- 
2.9.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v10 5/5] igt/kms_busy.c: Use new igt_spin_batch
  2016-11-23 10:59 i-g-t dummyload/spin batch v10 Abdiel Janulgue
                   ` (3 preceding siblings ...)
  2016-11-23 10:59 ` [i-g-t PATCH v10 4/5] igt/kms_flip: " Abdiel Janulgue
@ 2016-11-23 10:59 ` Abdiel Janulgue
  4 siblings, 0 replies; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-23 10:59 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

v7: Adapt to api rename
v8: Tidy up finish_fb_busy (Chris Wilson)
v10: Adapt to api rename

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 tests/kms_busy.c | 80 ++++----------------------------------------------------
 1 file changed, 5 insertions(+), 75 deletions(-)

diff --git a/tests/kms_busy.c b/tests/kms_busy.c
index b555f99..3627e8e 100644
--- a/tests/kms_busy.c
+++ b/tests/kms_busy.c
@@ -78,80 +78,11 @@ static void do_cleanup_display(igt_display_t *dpy)
 	igt_display_commit2(dpy, dpy->is_atomic ? COMMIT_ATOMIC : COMMIT_LEGACY);
 }
 
-static uint32_t *
-make_fb_busy(igt_display_t *dpy, unsigned ring, const struct igt_fb *fb)
-{
-	const int gen = intel_gen(intel_get_drm_devid(dpy->drm_fd));
-	struct drm_i915_gem_exec_object2 obj[2];
-#define SCRATCH 0
-#define BATCH 1
-	struct drm_i915_gem_relocation_entry reloc[2];
-	struct drm_i915_gem_execbuffer2 execbuf;
-	uint32_t *batch;
-	int i;
-
-	memset(&execbuf, 0, sizeof(execbuf));
-	execbuf.buffers_ptr = (uintptr_t)obj;
-	execbuf.buffer_count = 2;
-	execbuf.flags = ring;
-
-	memset(obj, 0, sizeof(obj));
-	obj[SCRATCH].handle = fb->gem_handle;
-
-	obj[BATCH].handle = gem_create(dpy->drm_fd, 4096);
-	obj[BATCH].relocs_ptr = (uintptr_t)reloc;
-	obj[BATCH].relocation_count = 2;
-	memset(reloc, 0, sizeof(reloc));
-	reloc[0].target_handle = obj[BATCH].handle; /* recurse */
-	reloc[0].presumed_offset = 0;
-	reloc[0].offset = sizeof(uint32_t);
-	reloc[0].delta = 0;
-	reloc[0].read_domains = I915_GEM_DOMAIN_COMMAND;
-	reloc[0].write_domain = 0;
-
-	batch = gem_mmap__wc(dpy->drm_fd,
-			     obj[BATCH].handle, 0, 4096, PROT_WRITE);
-	gem_set_domain(dpy->drm_fd, obj[BATCH].handle,
-		       I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
-
-	batch[i = 0] = 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[0].delta = 1;
-		}
-	}
-
-	/* dummy write to fb */
-	reloc[1].target_handle = obj[SCRATCH].handle;
-	reloc[1].presumed_offset = 0;
-	reloc[1].offset = 1024;
-	reloc[1].delta = 0;
-	reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;
-	reloc[1].write_domain = I915_GEM_DOMAIN_RENDER;
-
-	gem_execbuf(dpy->drm_fd, &execbuf);
-	gem_close(dpy->drm_fd, obj[BATCH].handle);
-
-	return batch;
-}
-
-static void finish_fb_busy(uint32_t *batch, int msecs)
+static void finish_fb_busy(igt_spin_t *spin, int msecs)
 {
 	struct timespec tv = { 0, msecs * 1000 * 1000 };
 	nanosleep(&tv, NULL);
-	batch[0] = MI_BATCH_BUFFER_END;
-	__sync_synchronize();
-	munmap(batch, 4096);
+	igt_spin_batch_end(spin);
 }
 
 static void sighandler(int sig)
@@ -165,9 +96,7 @@ static void flip_to_fb(igt_display_t *dpy, int pipe,
 	struct pollfd pfd = { .fd = dpy->drm_fd, .events = POLLIN };
 	struct timespec tv = { 1, 0 };
 	struct drm_event_vblank ev;
-	uint32_t *batch;
-
-	batch = make_fb_busy(dpy, ring, fb);
+	igt_spin_t *t = igt_spin_batch_new(dpy->drm_fd, ring, fb->gem_handle);
 	igt_fork(child, 1) {
 		igt_assert(gem_bo_busy(dpy->drm_fd, fb->gem_handle));
 		do_or_die(drmModePageFlip(dpy->drm_fd,
@@ -179,7 +108,8 @@ static void flip_to_fb(igt_display_t *dpy, int pipe,
 	}
 	igt_assert_f(nanosleep(&tv, NULL) == -1,
 		     "flip to %s blocked waiting for busy fb", name);
-	finish_fb_busy(batch, 2*TIMEOUT);
+	finish_fb_busy(t, 2*TIMEOUT);
+	igt_spin_batch_free(dpy->drm_fd, t);
 	igt_waitchildren();
 	igt_assert(read(dpy->drm_fd, &ev, sizeof(ev)) == sizeof(ev));
 	igt_assert(poll(&pfd, 1, 0) == 0);
-- 
2.9.3

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [i-g-t PATCH v10 4/5] igt/kms_flip: Use new igt_spin_batch
  2016-11-23 10:59 ` [i-g-t PATCH v10 4/5] igt/kms_flip: " Abdiel Janulgue
@ 2016-11-23 11:35   ` Chris Wilson
  0 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2016-11-23 11:35 UTC (permalink / raw)
  To: Abdiel Janulgue; +Cc: Daniel Vetter, intel-gfx

On Wed, Nov 23, 2016 at 12:59:42PM +0200, Abdiel Janulgue wrote:
> @@ -933,8 +755,13 @@ static unsigned int run_test_step(struct test_output *o)
>  	if (o->flags & TEST_MODESET)
>  		igt_assert(set_mode(o, o->fb_ids[o->current_fb_id], 0, 0) == 0);
>  
> -	if (o->flags & TEST_DPMS)
> +	if (o->flags & TEST_DPMS) {
> +		if (spin_rcs)
> +			igt_spin_batch_end(spin_rcs);
> +		if (spin_bcs)
> +			igt_spin_batch_end(spin_bcs);
>  		set_dpms(o, DRM_MODE_DPMS_ON);

This is subtly different as the set_dpms() is now called with an idle
bo. Now, set_dpms() may or may not block so calling it first then
igt_spin_batch_end() may deadlock, so this requires a set_timeout first
followed by end afterwards.
> +	}
>  
>  	if (o->flags & TEST_VBLANK_RACE) {
>  		struct vblank_reply reply;
> @@ -967,8 +794,13 @@ static unsigned int run_test_step(struct test_output *o)
>  		igt_assert(__wait_for_vblank(TEST_VBLANK_BLOCK, o->pipe, 1, 0, &reply) == 0);
>  	}
>  
> -	if (do_flip)
> +	if (do_flip) {
>  		do_or_die(do_page_flip(o, new_fb_id, !(o->flags & TEST_NOEVENT)));
> +		if (spin_rcs)
> +			igt_spin_batch_end(spin_rcs);
> +		if (spin_bcs)
> +			igt_spin_batch_end(spin_bcs);

Hmm, these need new_fb_id to be busy (separate tests for current /
both), I think you made current busy instead.

Order is good here (i.e. queue flip whilst busy). However, better would
be to delay the batch completion for a vblank just to stress the code
that little bit harder. (Even an assert that flip / bo are still busy as
we handle the vblank and complete the batch.)
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [i-g-t PATCH v10 2/5] lib: add igt_dummyload
  2016-11-23 10:59 ` [i-g-t PATCH v10 2/5] lib: add igt_dummyload Abdiel Janulgue
@ 2016-11-23 11:47   ` Chris Wilson
  2016-11-23 15:53     ` [i-g-t PATCH v11 " Abdiel Janulgue
  0 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2016-11-23 11:47 UTC (permalink / raw)
  To: Abdiel Janulgue; +Cc: Daniel Vetter, intel-gfx

On Wed, Nov 23, 2016 at 12:59:40PM +0200, Abdiel Janulgue wrote:
> A lot of igt testcases need some GPU workload to make sure a race
> window is big enough. Unfortunately having a fixed amount of
> workload leads to spurious test failures or overly long runtimes
> on some fast/slow platforms. This library contains functionality
> to submit GPU workloads that should consume exactly a specific
> amount of time.
> 
> v2 : Add recursive batch feature from Chris
> v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch
>      by adding a dummy reloc to the bo as suggested by Ville.
> v4:  Fix dependency reloc as write instead of read (Ville).
>      Fix wrong handling of batchbuffer start on ILK causing
>      test failure
> v5:  Convert kms_busy to use this api
> v6:  Add this library to docs
> v7:  Document global use of batch, reuse defines
>      Minor code cleanups.
>      Rename igt_spin_batch and igt_post_spin_batch to
>      igt_spin_batch_new and igt_spin_batch_free
>      respectively (Tomeu Vizoso).
>      Fix error in dependency relocation handling in HSW causing
>      tests to fail.
> v8:  Restore correct order of objects in the execbuffer. Batch
>      object should always be last.
> v9 : Add helper to terminate batch manually
> v10: Split timeout function. Clarify function names (Chris)
> 
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: tomeu@tomeuvizoso.net
> Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
> ---
>  .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
>  lib/Makefile.sources                               |   2 +
>  lib/igt.h                                          |   1 +
>  lib/igt_dummyload.c                                | 299 +++++++++++++++++++++
>  lib/igt_dummyload.h                                |  47 ++++
>  5 files changed, 350 insertions(+)
>  create mode 100644 lib/igt_dummyload.c
>  create mode 100644 lib/igt_dummyload.h
> 
> diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> index c862f2a..55902ab 100644
> --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> @@ -32,6 +32,7 @@
>      <xi:include href="xml/intel_io.xml"/>
>      <xi:include href="xml/igt_vc4.xml"/>
>      <xi:include href="xml/igt_vgem.xml"/>
> +    <xi:include href="xml/igt_dummyload.xml"/>
>    </chapter>
>    <xi:include href="xml/igt_test_programs.xml"/>
>  
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index e8e277b..7fc5ec2 100644
> --- a/lib/Makefile.sources
> +++ b/lib/Makefile.sources
> @@ -75,6 +75,8 @@ lib_source_list =	 	\
>  	igt_draw.h		\
>  	igt_pm.c		\
>  	igt_pm.h		\
> +	igt_dummyload.c		\
> +	igt_dummyload.h		\
>  	uwildmat/uwildmat.h	\
>  	uwildmat/uwildmat.c	\
>  	$(NULL)
> diff --git a/lib/igt.h b/lib/igt.h
> index d751f24..a0028d5 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -32,6 +32,7 @@
>  #include "igt_core.h"
>  #include "igt_debugfs.h"
>  #include "igt_draw.h"
> +#include "igt_dummyload.h"
>  #include "igt_fb.h"
>  #include "igt_gt.h"
>  #include "igt_kms.h"
> diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
> new file mode 100644
> index 0000000..afb0851
> --- /dev/null
> +++ b/lib/igt_dummyload.c
> @@ -0,0 +1,299 @@
> +/*
> + * Copyright © 2016 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.
> + *
> + */
> +
> +#include "igt.h"
> +#include "igt_dummyload.h"
> +#include <time.h>
> +#include <signal.h>
> +#include <sys/syscall.h>
> +
> +/**
> + * SECTION:igt_dummyload
> + * @short_description: Library for submitting GPU workloads
> + * @title: Dummyload
> + * @include: igt.h
> + *
> + * A lot of igt testcases need some GPU workload to make sure a race window is
> + * big enough. Unfortunately having a fixed amount of workload leads to
> + * spurious test failures or overly long runtimes on some fast/slow platforms.
> + * This library contains functionality to submit GPU workloads that should
> + * consume exactly a specific amount of time.
> + */
> +
> +#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
> +#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
> +
> +#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
> +
> +static const int bo_size = 4096;
> +
> +static void
> +fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
> +	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
> +{
> +	memset(obj, 0, sizeof(*obj));
> +	obj->handle = gem_handle;
> +	obj->relocation_count = count;
> +	obj->relocs_ptr = (uintptr_t)relocs;
> +}
> +
> +static void
> +fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
> +	   uint32_t gem_handle, uint32_t offset,
> +	   uint32_t read_domains, uint32_t write_domains)
> +{
> +	reloc->target_handle = gem_handle;
> +	reloc->delta = 0;
> +	reloc->offset = offset * sizeof(uint32_t);
> +	reloc->presumed_offset = 0;
> +	reloc->read_domains = read_domains;
> +	reloc->write_domain = write_domains;
> +}
> +
> +/*
> + * Needs to be global. Signal handlers don't accept arguments
> + */
> +static uint32_t *batch;
> +
> +static uint32_t emit_recursive_batch(int fd, int engine, unsigned dep_handle)
> +{
> +	const int gen = intel_gen(intel_get_drm_devid(fd));
> +	struct drm_i915_gem_exec_object2 obj[2];
> +	struct drm_i915_gem_relocation_entry relocs[2];
> +	struct drm_i915_gem_execbuffer2 execbuf;
> +	unsigned engines[16];
> +	unsigned nengine, handle;
> +	int i = 0, reloc_count = 0, buf_count = 0;
> +
> +	buf_count = 0;
> +	nengine = 0;
> +	if (engine < 0) {
> +		for_each_engine(fd, engine)
> +			if (engine)
> +				engines[nengine++] = engine;
> +	} else {
> +		gem_require_ring(fd, engine);
> +		engines[nengine++] = engine;
> +	}
> +	igt_require(nengine);
> +
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	memset(obj, 0, sizeof(obj));
> +	memset(relocs, 0, sizeof(relocs));
> +
> +	execbuf.buffers_ptr = (uintptr_t) obj;
> +	handle = gem_create(fd, bo_size);
> +	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
> +	igt_assert(batch);
> +	gem_set_domain(fd, handle,
> +			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> +
> +	if (dep_handle > 0) {
> +		igt_assert(nengine == 1);

I have some examples of using a spinning batch with a write hazard
across multiple engines... I guess you haven't yet looked at enough
use cases ;)

> +		/* dummy write to dependency */
> +		fill_object(&obj[buf_count], dep_handle, NULL, 0);
> +		buf_count++;
> +
> +		fill_reloc(&relocs[reloc_count], dep_handle, 256,
> +			   I915_GEM_DOMAIN_RENDER,
> +			   I915_GEM_DOMAIN_RENDER);
> +		reloc_count++;
> +	}
> +
> +	if (gen >= 8) {
> +		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
> +		/* recurse */
> +		fill_reloc(&relocs[reloc_count], handle, i,
> +			   I915_GEM_DOMAIN_COMMAND, 0);
> +		batch[i++] = 0;
> +		batch[i++] = 0;
> +	} else if (gen >= 6) {
> +		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
> +		/* recurse */
> +		fill_reloc(&relocs[reloc_count], handle, i,
> +			   I915_GEM_DOMAIN_COMMAND, 0);
> +		batch[i++] = 0;
> +	} else {
> +		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
> +			((gen < 4) ? 1 : 0);
> +		/* recurse */
> +		fill_reloc(&relocs[reloc_count], handle, i,
> +			   I915_GEM_DOMAIN_COMMAND, 0);
> +		batch[i++] = 0;
> +		if (gen < 4)
> +			relocs[reloc_count].delta = 1;
> +	}
> +	reloc_count++;
> +
> +	fill_object(&obj[buf_count], handle, relocs, reloc_count);
> +	buf_count++;
> +
> +	for (i = 0; i < nengine; i++) {
> +		execbuf.flags &= ~ENGINE_MASK;
> +		execbuf.flags = engines[i];
> +		execbuf.buffer_count = buf_count;
> +		gem_execbuf(fd, &execbuf);
> +	}
> +
> +	return handle;
> +}
> +
> +static void exit_batch_handler(int sig, siginfo_t *info, void *spin)
> +{
> +	*batch = MI_BATCH_BUFFER_END;
> +	__sync_synchronize();
> +}
> +
> +/**
> + * igt_spin_batch_new:
> + * @fd: open i915 drm file descriptor
> + * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
> + *          than 0, execute on all available rings.
> + * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
> + *              relocation entry to this buffer within the batch.
> + *
> + * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
> + * contains the batch's handle that can be waited upon. The returned structure
> + * must be passed to igt_spin_batch_free() for post-processing.
> + *
> + * Returns:
> + * Structure with helper internal state for igt_spin_batch_free().
> + */
> +igt_spin_t *
> +igt_spin_batch_new(int fd, int engine, unsigned dep_handle)
> +{
> +	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
> +	uint32_t handle = emit_recursive_batch(fd, engine, dep_handle);
> +	int64_t wait_timeout = 0;
> +	igt_assert_eq(gem_wait(fd, handle, &wait_timeout), -ETIME);

This is gem_bo_busy(). The gem_wait() was for sanitychecking gem_wait.c
test setup.

A really useful improvement (especially for a library function) is to
hook into an exit handler to ensure that all submitted batches are
completed. You can hook into gem_quiescent_gpu() (as that is a useful
catch).

> +
> +	spin->handle = handle;
> +	spin->batch = batch;
> +	spin->timer = NULL;
> +
> +	return spin;
> +}
> +
> +/**
> + * igt_spin_batch_set_timeout:
> + * @spin: spin batch state from igt_spin_batch_new()
> + * @ns: amount of time in nanoseconds the batch continues to execute
> + *      before finishing.
> + *
> + * Specify a timeout. This ends the recursive batch associated with @spin after
> + * the timeout has elapsed.
> + */
> +void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
> +{
> +	timer_t timer;
> +	struct sigevent sev;
> +	struct sigaction act;
> +	struct itimerspec its;
> +
> +	igt_assert(ns > 0);
> +	if (!spin)
> +		return;
> +
> +	memset(&sev, 0, sizeof(sev));
> +	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
> +	sev.sigev_notify_thread_id = gettid();
> +	sev.sigev_signo = SIGRTMIN + 1;
> +	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
> +	igt_assert(timer > 0);
> +
> +	memset(&act, 0, sizeof(act));
> +	act.sa_sigaction = exit_batch_handler;
> +	act.sa_flags = SA_SIGINFO;
> +	igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0);
> +
> +	memset(&its, 0, sizeof(its));
> +	its.it_value.tv_sec = ns / NSEC_PER_SEC;
> +	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
> +	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
> +
> +	spin->timer = timer;
> +}
> +
> +/**
> + * igt_spin_batch_end:
> + * @spin: spin batch state from igt_spin_batch_new()
> + *
> + * End the recursive batch associated with @spin manually.
> + */
> +void igt_spin_batch_end(igt_spin_t *spin)
> +{
> +	if (!spin)
> +		return;
> +
> +	if (spin->handle > 0)
> +		exit_batch_handler(0, NULL, NULL);

We should never create an igt_spin_t with an invalid handle. All the
spin->handle > 0 are pointless. And you already exploded on !spin during
construction.

Please make your mind up between testing for a NULL spin in the caller
or callee.

> +/**
> + * igt_spin_batch_free:
> + * @fd: open i915 drm file descriptor
> + * @spin: spin batch state from igt_spin_batch_new()
> + *
> + * This function does the necessary post-processing after starting a recursive
> + * batch with igt_spin_batch_new().
> + */
> +void igt_spin_batch_free(int fd, igt_spin_t *spin)
> +{
> +	if (!spin)
> +		return;
> +
> +	if (spin->handle > 0)
> +		gem_close(fd, spin->handle);
> +
> +	if (spin->timer > 0)
> +		timer_delete(spin->timer);

Awooga! Before you unmap it, it is imperative that you ensure the batch
is terminated with BBE.

> +	munmap(spin->batch, bo_size);
> +	free(spin);
> +}
> +
> +/**
> + * igt_spin_batch_wait:
> + * @fd: open i915 drm file descriptor
> + * @ns: amount of time in nanoseconds the batch continues to execute
> + *      before finishing.
> + * @engine: ring to execute batch OR'd with execbuf flags. If value is less
> + *          than 0, execute on all available rings.
> + * @dep_handle: handle to a buffer object dependency. If greater than 0, include
> + *              this buffer on the wait dependency
> + *
> + * Convenience function similar to igt_spin_batch_new() then setting the timeout
> + * with igt_spin_batch_set_timeout(), but waits on the recursive batch to finish
> + * instead of returning right away. The function also does the necessary
> + * post-processing automatically.
> + */
> +void igt_spin_batch_wait(int fd, int64_t ns, int engine, unsigned dep_handle)
> +{
> +	igt_spin_t *spin = igt_spin_batch_new(fd, engine, dep_handle);
> +	int64_t wait_timeout = ns + (0.5 * NSEC_PER_SEC);
> +	igt_spin_batch_set_timeout(spin, wait_timeout);
> +	igt_assert_eq(gem_wait(fd, spin->handle, &wait_timeout), 0);

This assert is interesting, but may fail simply due to scheduling onto
another cpu.

This whole function is a risky nanosleep()... Seems pointless, the idea
is to create an asynchronous load on the GPU that we later terminate or
use in some creative fashion.

> +
> +	igt_spin_batch_free(fd, spin);
> +}

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v11 2/5] lib: add igt_dummyload
  2016-11-23 11:47   ` Chris Wilson
@ 2016-11-23 15:53     ` Abdiel Janulgue
  2016-11-23 16:17       ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-23 15:53 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

A lot of igt testcases need some GPU workload to make sure a race
window is big enough. Unfortunately having a fixed amount of
workload leads to spurious test failures or overly long runtimes
on some fast/slow platforms. This library contains functionality
to submit GPU workloads that should consume exactly a specific
amount of time.

v2 : Add recursive batch feature from Chris
v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch
     by adding a dummy reloc to the bo as suggested by Ville.
v4:  Fix dependency reloc as write instead of read (Ville).
     Fix wrong handling of batchbuffer start on ILK causing
     test failure
v5:  Convert kms_busy to use this api
v6:  Add this library to docs
v7:  Document global use of batch, reuse defines
     Minor code cleanups.
     Rename igt_spin_batch and igt_post_spin_batch to
     igt_spin_batch_new and igt_spin_batch_free
     respectively (Tomeu Vizoso).
     Fix error in dependency relocation handling in HSW causing
     tests to fail.
v8:  Restore correct order of objects in the execbuffer. Batch
     object should always be last.
v9 : Add helper to terminate batch manually
v10: Split timeout function. Clarify function names (Chris)
v11: From Chris:
     * Add gem_quiescent_gpu exit handler
     * Use gem_bo_busy
     * Skip spin->handle > 0 checks
     * Ensure terminate batch on free
     * Remove igt_spin_batch_wait
     * Remove single-ring limitation

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: tomeu@tomeuvizoso.net
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/igt.h                                          |   1 +
 lib/igt_dummyload.c                                | 283 +++++++++++++++++++++
 lib/igt_dummyload.h                                |  44 ++++
 5 files changed, 331 insertions(+)
 create mode 100644 lib/igt_dummyload.c
 create mode 100644 lib/igt_dummyload.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c862f2a..55902ab 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -32,6 +32,7 @@
     <xi:include href="xml/intel_io.xml"/>
     <xi:include href="xml/igt_vc4.xml"/>
     <xi:include href="xml/igt_vgem.xml"/>
+    <xi:include href="xml/igt_dummyload.xml"/>
   </chapter>
   <xi:include href="xml/igt_test_programs.xml"/>
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e8e277b..7fc5ec2 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -75,6 +75,8 @@ lib_source_list =	 	\
 	igt_draw.h		\
 	igt_pm.c		\
 	igt_pm.h		\
+	igt_dummyload.c		\
+	igt_dummyload.h		\
 	uwildmat/uwildmat.h	\
 	uwildmat/uwildmat.c	\
 	$(NULL)
diff --git a/lib/igt.h b/lib/igt.h
index d751f24..a0028d5 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -32,6 +32,7 @@
 #include "igt_core.h"
 #include "igt_debugfs.h"
 #include "igt_draw.h"
+#include "igt_dummyload.h"
 #include "igt_fb.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
new file mode 100644
index 0000000..7068bcb
--- /dev/null
+++ b/lib/igt_dummyload.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "igt.h"
+#include "igt_dummyload.h"
+#include <time.h>
+#include <signal.h>
+#include <sys/syscall.h>
+
+/**
+ * SECTION:igt_dummyload
+ * @short_description: Library for submitting GPU workloads
+ * @title: Dummyload
+ * @include: igt.h
+ *
+ * A lot of igt testcases need some GPU workload to make sure a race window is
+ * big enough. Unfortunately having a fixed amount of workload leads to
+ * spurious test failures or overly long runtimes on some fast/slow platforms.
+ * This library contains functionality to submit GPU workloads that should
+ * consume exactly a specific amount of time.
+ */
+
+#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
+#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
+
+#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
+
+static const int bo_size = 4096;
+
+static void
+fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
+	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
+{
+	memset(obj, 0, sizeof(*obj));
+	obj->handle = gem_handle;
+	obj->relocation_count = count;
+	obj->relocs_ptr = (uintptr_t)relocs;
+}
+
+static void
+fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+	   uint32_t gem_handle, uint32_t offset,
+	   uint32_t read_domains, uint32_t write_domains)
+{
+	reloc->target_handle = gem_handle;
+	reloc->delta = 0;
+	reloc->offset = offset * sizeof(uint32_t);
+	reloc->presumed_offset = 0;
+	reloc->read_domains = read_domains;
+	reloc->write_domain = write_domains;
+}
+
+/*
+ * Needs to be global. Signal handlers don't accept arguments
+ */
+static uint32_t *batch;
+
+static uint32_t emit_recursive_batch(int fd, int engine, unsigned dep_handle)
+{
+	const int gen = intel_gen(intel_get_drm_devid(fd));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry relocs[2];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	unsigned engines[16];
+	unsigned nengine, handle;
+	int i = 0, reloc_count = 0, buf_count = 0;
+
+	buf_count = 0;
+	nengine = 0;
+	if (engine < 0) {
+		for_each_engine(fd, engine)
+			if (engine)
+				engines[nengine++] = engine;
+	} else {
+		gem_require_ring(fd, engine);
+		engines[nengine++] = engine;
+	}
+	igt_require(nengine);
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	memset(obj, 0, sizeof(obj));
+	memset(relocs, 0, sizeof(relocs));
+
+	execbuf.buffers_ptr = (uintptr_t) obj;
+	handle = gem_create(fd, bo_size);
+	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
+	igt_assert(batch);
+	gem_set_domain(fd, handle,
+			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+	if (dep_handle > 0) {
+		/* dummy write to dependency */
+		fill_object(&obj[buf_count], dep_handle, NULL, 0);
+		buf_count++;
+
+		fill_reloc(&relocs[reloc_count], dep_handle, 256,
+			   I915_GEM_DOMAIN_RENDER,
+			   I915_GEM_DOMAIN_RENDER);
+		reloc_count++;
+	}
+
+	if (gen >= 8) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		batch[i++] = 0;
+	} else if (gen >= 6) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+	} else {
+		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
+			((gen < 4) ? 1 : 0);
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		if (gen < 4)
+			relocs[reloc_count].delta = 1;
+	}
+	reloc_count++;
+
+	fill_object(&obj[buf_count], handle, relocs, reloc_count);
+	buf_count++;
+
+	for (i = 0; i < nengine; i++) {
+		execbuf.flags = engines[i];
+		execbuf.flags &= ~ENGINE_MASK;
+		execbuf.buffer_count = buf_count;
+		gem_execbuf(fd, &execbuf);
+	}
+
+	return handle;
+}
+
+static void exit_batch_handler(int sig, siginfo_t *info, void *spin)
+{
+	*batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+static int at_exit_drm_fd = -1;
+
+static void quiescent_gpu_at_exit(int sig)
+{
+	if (at_exit_drm_fd < 0)
+		return;
+
+	gem_quiescent_gpu(at_exit_drm_fd);
+	at_exit_drm_fd = -1;
+}
+
+/**
+ * igt_spin_batch_new:
+ * @fd: open i915 drm file descriptor
+ * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
+ *          than 0, execute on all available rings.
+ * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
+ *              relocation entry to this buffer within the batch.
+ *
+ * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
+ * contains the batch's handle that can be waited upon. The returned structure
+ * must be passed to igt_spin_batch_free() for post-processing.
+ *
+ * Returns:
+ * Structure with helper internal state for igt_spin_batch_free().
+ */
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned dep_handle)
+{
+	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
+	uint32_t handle = emit_recursive_batch(fd, engine, dep_handle);
+	igt_assert(gem_bo_busy(fd, handle));
+	at_exit_drm_fd = fd;
+	igt_install_exit_handler(quiescent_gpu_at_exit);
+
+	spin->handle = handle;
+	spin->batch = batch;
+	spin->timer = NULL;
+
+	return spin;
+}
+
+/**
+ * igt_spin_batch_set_timeout:
+ * @spin: spin batch state from igt_spin_batch_new()
+ * @ns: amount of time in nanoseconds the batch continues to execute
+ *      before finishing.
+ *
+ * Specify a timeout. This ends the recursive batch associated with @spin after
+ * the timeout has elapsed.
+ */
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
+{
+	timer_t timer;
+	struct sigevent sev;
+	struct sigaction act;
+	struct itimerspec its;
+
+	igt_assert(ns > 0);
+	if (!spin)
+		return;
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+	sev.sigev_notify_thread_id = gettid();
+	sev.sigev_signo = SIGRTMIN + 1;
+	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
+	igt_assert(timer > 0);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = exit_batch_handler;
+	act.sa_flags = SA_SIGINFO;
+	igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0);
+
+	memset(&its, 0, sizeof(its));
+	its.it_value.tv_sec = ns / NSEC_PER_SEC;
+	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
+	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
+
+	spin->timer = timer;
+}
+
+/**
+ * igt_spin_batch_end:
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * End the recursive batch associated with @spin manually.
+ */
+void igt_spin_batch_end(igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	exit_batch_handler(0, NULL, NULL);
+}
+
+/**
+ * igt_spin_batch_free:
+ * @fd: open i915 drm file descriptor
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * This function does the necessary post-processing after starting a recursive
+ * batch with igt_spin_batch_new().
+ */
+void igt_spin_batch_free(int fd, igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	if (spin->timer > 0)
+		timer_delete(spin->timer);
+
+	exit_batch_handler(0, NULL, NULL);
+	munmap(spin->batch, bo_size);
+	gem_close(fd, spin->handle);
+	free(spin);
+}
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
new file mode 100644
index 0000000..2aebc70
--- /dev/null
+++ b/lib/igt_dummyload.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#ifndef __IGT_DUMMYLOAD_H__
+#define __IGT_DUMMYLOAD_H__
+
+typedef struct igt_spin {
+	unsigned handle;
+	uint32_t *batch;
+	timer_t timer;
+} igt_spin_t;
+
+
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned dep_handle);
+
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns);
+
+void igt_spin_batch_end(igt_spin_t *spin);
+
+void igt_spin_batch_free(int fd, igt_spin_t *spin);
+
+#endif /* __IGT_DUMMYLOAD_H__ */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [i-g-t PATCH v11 2/5] lib: add igt_dummyload
  2016-11-23 15:53     ` [i-g-t PATCH v11 " Abdiel Janulgue
@ 2016-11-23 16:17       ` Chris Wilson
  2016-11-24 10:16         ` [i-g-t PATCH v12 " Abdiel Janulgue
  0 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2016-11-23 16:17 UTC (permalink / raw)
  To: Abdiel Janulgue; +Cc: Daniel Vetter, intel-gfx

On Wed, Nov 23, 2016 at 05:53:50PM +0200, Abdiel Janulgue wrote:
> +static int at_exit_drm_fd = -1;
> +
> +static void quiescent_gpu_at_exit(int sig)
> +{
> +	if (at_exit_drm_fd < 0)
> +		return;
> +
> +	gem_quiescent_gpu(at_exit_drm_fd);
> +	at_exit_drm_fd = -1;
> +}
> +
> +/**
> + * igt_spin_batch_new:
> + * @fd: open i915 drm file descriptor
> + * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
> + *          than 0, execute on all available rings.
> + * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
> + *              relocation entry to this buffer within the batch.
> + *
> + * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
> + * contains the batch's handle that can be waited upon. The returned structure
> + * must be passed to igt_spin_batch_free() for post-processing.
> + *
> + * Returns:
> + * Structure with helper internal state for igt_spin_batch_free().
> + */
> +igt_spin_t *
> +igt_spin_batch_new(int fd, int engine, unsigned dep_handle)
> +{
> +	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
> +	uint32_t handle = emit_recursive_batch(fd, engine, dep_handle);
> +	igt_assert(gem_bo_busy(fd, handle));
> +	at_exit_drm_fd = fd;
> +	igt_install_exit_handler(quiescent_gpu_at_exit);

We already do igt_install_exit_handler(quiescent_gpu_at_exit); doing a
plain one ourselves still incurs a GPU hang if the user hits ^C. (And we
are installing one for every new spinner.)

What I meant was that if we kept a list of active spinners and walked
that list from gem_quiescent_gpu() we could leverage the existing
infrastructure to ensure that the GPU was idled as kick as possible
after a failed/interrupted test (without GPU hangs causing havoc).

P.S. imagine running checkpatch.pl and keeping in the habit of using the
kernel CodingStyle.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v12 2/5] lib: add igt_dummyload
  2016-11-23 16:17       ` Chris Wilson
@ 2016-11-24 10:16         ` Abdiel Janulgue
  2016-11-25  9:17           ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-24 10:16 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

A lot of igt testcases need some GPU workload to make sure a race
window is big enough. Unfortunately having a fixed amount of
workload leads to spurious test failures or overly long runtimes
on some fast/slow platforms. This library contains functionality
to submit GPU workloads that should consume exactly a specific
amount of time.

v2 : Add recursive batch feature from Chris
v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch
     by adding a dummy reloc to the bo as suggested by Ville.
v4:  Fix dependency reloc as write instead of read (Ville).
     Fix wrong handling of batchbuffer start on ILK causing
     test failure
v5:  Convert kms_busy to use this api
v6:  Add this library to docs
v7:  Document global use of batch, reuse defines
     Minor code cleanups.
     Rename igt_spin_batch and igt_post_spin_batch to
     igt_spin_batch_new and igt_spin_batch_free
     respectively (Tomeu Vizoso).
     Fix error in dependency relocation handling in HSW causing
     tests to fail.
v8:  Restore correct order of objects in the execbuffer. Batch
     object should always be last.
v9 : Add helper to terminate batch manually
v10: Split timeout function. Clarify function names (Chris)
v11: From Chris:
     * Add gem_quiescent_gpu exit handler
     * Use gem_bo_busy
     * Skip spin->handle > 0 checks
     * Ensure terminate batch on free
     * Remove igt_spin_batch_wait
     * Remove single-ring limitation
v12: Hook into gem_quiescent_gpu exit handler to idle the GPU if
     the user terminates tests with ^C

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: tomeu@tomeuvizoso.net
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/drmtest.c                                      |   3 +
 lib/igt.h                                          |   1 +
 lib/igt_dummyload.c                                | 302 +++++++++++++++++++++
 lib/igt_dummyload.h                                |  46 ++++
 6 files changed, 355 insertions(+)
 create mode 100644 lib/igt_dummyload.c
 create mode 100644 lib/igt_dummyload.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c862f2a..55902ab 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -32,6 +32,7 @@
     <xi:include href="xml/intel_io.xml"/>
     <xi:include href="xml/igt_vc4.xml"/>
     <xi:include href="xml/igt_vgem.xml"/>
+    <xi:include href="xml/igt_dummyload.xml"/>
   </chapter>
   <xi:include href="xml/igt_test_programs.xml"/>
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e8e277b..7fc5ec2 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -75,6 +75,8 @@ lib_source_list =	 	\
 	igt_draw.h		\
 	igt_pm.c		\
 	igt_pm.h		\
+	igt_dummyload.c		\
+	igt_dummyload.h		\
 	uwildmat/uwildmat.h	\
 	uwildmat/uwildmat.c	\
 	$(NULL)
diff --git a/lib/drmtest.c b/lib/drmtest.c
index 44abc7e..be1dc93 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -57,6 +57,7 @@
 #include "config.h"
 #include "intel_reg.h"
 #include "ioctl_wrappers.h"
+#include "igt_dummyload.h"
 
 /**
  * SECTION:drmtest
@@ -159,6 +160,8 @@ void gem_quiescent_gpu(int fd)
 	struct drm_i915_gem_exec_object2 obj;
 	unsigned ring;
 
+	igt_terminate_spin_batches();
+
 	memset(&obj, 0, sizeof(obj));
 	obj.handle = gem_create(fd, 4096);
 	gem_write(fd, obj.handle, 0, &bbe, sizeof(&bbe));
diff --git a/lib/igt.h b/lib/igt.h
index d751f24..a0028d5 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -32,6 +32,7 @@
 #include "igt_core.h"
 #include "igt_debugfs.h"
 #include "igt_draw.h"
+#include "igt_dummyload.h"
 #include "igt_fb.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
new file mode 100644
index 0000000..8270c38
--- /dev/null
+++ b/lib/igt_dummyload.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "igt.h"
+#include "igt_dummyload.h"
+#include <time.h>
+#include <signal.h>
+#include <sys/syscall.h>
+
+/**
+ * SECTION:igt_dummyload
+ * @short_description: Library for submitting GPU workloads
+ * @title: Dummyload
+ * @include: igt.h
+ *
+ * A lot of igt testcases need some GPU workload to make sure a race window is
+ * big enough. Unfortunately having a fixed amount of workload leads to
+ * spurious test failures or overly long runtimes on some fast/slow platforms.
+ * This library contains functionality to submit GPU workloads that should
+ * consume exactly a specific amount of time.
+ */
+
+#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
+#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
+
+#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
+
+static const int bo_size = 4096;
+
+static void
+fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
+	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
+{
+	memset(obj, 0, sizeof(*obj));
+	obj->handle = gem_handle;
+	obj->relocation_count = count;
+	obj->relocs_ptr = (uintptr_t)relocs;
+}
+
+static void
+fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+	   uint32_t gem_handle, uint32_t offset,
+	   uint32_t read_domains, uint32_t write_domains)
+{
+	reloc->target_handle = gem_handle;
+	reloc->delta = 0;
+	reloc->offset = offset * sizeof(uint32_t);
+	reloc->presumed_offset = 0;
+	reloc->read_domains = read_domains;
+	reloc->write_domain = write_domains;
+}
+
+/*
+ * Needs to be global. Signal handlers don't accept arguments
+ */
+static uint32_t *batch;
+
+static uint32_t emit_recursive_batch(int fd, int engine,
+				     unsigned int dep_handle)
+{
+	const int gen = intel_gen(intel_get_drm_devid(fd));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry relocs[2];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	unsigned int engines[16];
+	unsigned int nengine, handle;
+	int i = 0, reloc_count = 0, buf_count = 0;
+
+	buf_count = 0;
+	nengine = 0;
+	if (engine < 0) {
+		for_each_engine(fd, engine)
+			if (engine)
+				engines[nengine++] = engine;
+	} else {
+		gem_require_ring(fd, engine);
+		engines[nengine++] = engine;
+	}
+	igt_require(nengine);
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	memset(obj, 0, sizeof(obj));
+	memset(relocs, 0, sizeof(relocs));
+
+	execbuf.buffers_ptr = (uintptr_t) obj;
+	handle = gem_create(fd, bo_size);
+	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
+	igt_assert(batch);
+	gem_set_domain(fd, handle,
+			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+	if (dep_handle > 0) {
+		/* dummy write to dependency */
+		fill_object(&obj[buf_count], dep_handle, NULL, 0);
+		buf_count++;
+
+		fill_reloc(&relocs[reloc_count], dep_handle, 256,
+			   I915_GEM_DOMAIN_RENDER,
+			   I915_GEM_DOMAIN_RENDER);
+		reloc_count++;
+	}
+
+	if (gen >= 8) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		batch[i++] = 0;
+	} else if (gen >= 6) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+	} else {
+		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
+			((gen < 4) ? 1 : 0);
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		if (gen < 4)
+			relocs[reloc_count].delta = 1;
+	}
+	reloc_count++;
+
+	fill_object(&obj[buf_count], handle, relocs, reloc_count);
+	buf_count++;
+
+	for (i = 0; i < nengine; i++) {
+		execbuf.flags = engines[i];
+		execbuf.flags &= ~ENGINE_MASK;
+		execbuf.buffer_count = buf_count;
+		gem_execbuf(fd, &execbuf);
+	}
+
+	return handle;
+}
+
+static void exit_batch_handler(int sig, siginfo_t *info, void *spin)
+{
+	*batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+int num_spin_objects;
+int spin_objects_sz;
+igt_spin_t **spin_objects;
+
+static void save_spin_batch(igt_spin_t *spin)
+{
+	if (num_spin_objects >= spin_objects_sz) {
+		if (!spin_objects_sz)
+			spin_objects_sz = 4;
+		else
+			spin_objects_sz *= 2;
+
+		spin_objects = realloc(spin_objects,
+				       sizeof(igt_spin_t *) * spin_objects_sz);
+		igt_assert(spin_objects);
+	}
+	spin_objects[num_spin_objects++] = spin;
+}
+
+void igt_terminate_spin_batches(void)
+{
+	int i;
+
+	for (i = 0; i <  num_spin_objects; i++)
+		igt_spin_batch_end(spin_objects[i]);
+}
+
+/**
+ * igt_spin_batch_new:
+ * @fd: open i915 drm file descriptor
+ * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
+ *          than 0, execute on all available rings.
+ * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
+ *              relocation entry to this buffer within the batch.
+ *
+ * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
+ * contains the batch's handle that can be waited upon. The returned structure
+ * must be passed to igt_spin_batch_free() for post-processing.
+ *
+ * Returns:
+ * Structure with helper internal state for igt_spin_batch_free().
+ */
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle)
+{
+	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
+	uint32_t handle = emit_recursive_batch(fd, engine, dep_handle);
+
+	igt_assert(gem_bo_busy(fd, handle));
+	spin->handle = handle;
+	spin->batch = batch;
+	spin->timer = NULL;
+	save_spin_batch(spin);
+
+	return spin;
+}
+
+/**
+ * igt_spin_batch_set_timeout:
+ * @spin: spin batch state from igt_spin_batch_new()
+ * @ns: amount of time in nanoseconds the batch continues to execute
+ *      before finishing.
+ *
+ * Specify a timeout. This ends the recursive batch associated with @spin after
+ * the timeout has elapsed.
+ */
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
+{
+	timer_t timer;
+	struct sigevent sev;
+	struct sigaction act;
+	struct itimerspec its;
+
+	igt_assert(ns > 0);
+	if (!spin)
+		return;
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+	sev.sigev_notify_thread_id = gettid();
+	sev.sigev_signo = SIGRTMIN + 1;
+	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
+	igt_assert(timer > 0);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = exit_batch_handler;
+	act.sa_flags = SA_SIGINFO;
+	igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0);
+
+	memset(&its, 0, sizeof(its));
+	its.it_value.tv_sec = ns / NSEC_PER_SEC;
+	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
+	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
+
+	spin->timer = timer;
+}
+
+/**
+ * igt_spin_batch_end:
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * End the recursive batch associated with @spin manually.
+ */
+void igt_spin_batch_end(igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	*spin->batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+/**
+ * igt_spin_batch_free:
+ * @fd: open i915 drm file descriptor
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * This function does the necessary post-processing after starting a recursive
+ * batch with igt_spin_batch_new().
+ */
+void igt_spin_batch_free(int fd, igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	if (spin->timer > 0)
+		timer_delete(spin->timer);
+
+	igt_spin_batch_end(spin);
+	munmap(spin->batch, bo_size);
+	gem_close(fd, spin->handle);
+	free(spin);
+
+	num_spin_objects--;
+}
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
new file mode 100644
index 0000000..a53a241
--- /dev/null
+++ b/lib/igt_dummyload.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#ifndef __IGT_DUMMYLOAD_H__
+#define __IGT_DUMMYLOAD_H__
+
+typedef struct igt_spin {
+	unsigned int handle;
+	uint32_t *batch;
+	timer_t timer;
+} igt_spin_t;
+
+
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle);
+
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns);
+
+void igt_spin_batch_end(igt_spin_t *spin);
+
+void igt_spin_batch_free(int fd, igt_spin_t *spin);
+
+void igt_terminate_spin_batches(void);
+
+#endif /* __IGT_DUMMYLOAD_H__ */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [i-g-t PATCH v12 2/5] lib: add igt_dummyload
  2016-11-24 10:16         ` [i-g-t PATCH v12 " Abdiel Janulgue
@ 2016-11-25  9:17           ` Chris Wilson
  2016-11-25 11:40             ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Abdiel Janulgue
  0 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2016-11-25  9:17 UTC (permalink / raw)
  To: Abdiel Janulgue; +Cc: Daniel Vetter, intel-gfx

On Thu, Nov 24, 2016 at 12:16:11PM +0200, Abdiel Janulgue wrote:
> A lot of igt testcases need some GPU workload to make sure a race
> window is big enough. Unfortunately having a fixed amount of
> workload leads to spurious test failures or overly long runtimes
> on some fast/slow platforms. This library contains functionality
> to submit GPU workloads that should consume exactly a specific
> amount of time.
> 
> v2 : Add recursive batch feature from Chris
> v3 : Drop auto-tuned stuff. Add bo dependecy to recursive batch
>      by adding a dummy reloc to the bo as suggested by Ville.
> v4:  Fix dependency reloc as write instead of read (Ville).
>      Fix wrong handling of batchbuffer start on ILK causing
>      test failure
> v5:  Convert kms_busy to use this api
> v6:  Add this library to docs
> v7:  Document global use of batch, reuse defines
>      Minor code cleanups.
>      Rename igt_spin_batch and igt_post_spin_batch to
>      igt_spin_batch_new and igt_spin_batch_free
>      respectively (Tomeu Vizoso).
>      Fix error in dependency relocation handling in HSW causing
>      tests to fail.
> v8:  Restore correct order of objects in the execbuffer. Batch
>      object should always be last.
> v9 : Add helper to terminate batch manually
> v10: Split timeout function. Clarify function names (Chris)
> v11: From Chris:
>      * Add gem_quiescent_gpu exit handler
>      * Use gem_bo_busy
>      * Skip spin->handle > 0 checks
>      * Ensure terminate batch on free
>      * Remove igt_spin_batch_wait
>      * Remove single-ring limitation
> v12: Hook into gem_quiescent_gpu exit handler to idle the GPU if
>      the user terminates tests with ^C
> 
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: tomeu@tomeuvizoso.net
> Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
> ---
> +/**
> + * igt_spin_batch_set_timeout:
> + * @spin: spin batch state from igt_spin_batch_new()
> + * @ns: amount of time in nanoseconds the batch continues to execute
> + *      before finishing.
> + *
> + * Specify a timeout. This ends the recursive batch associated with @spin after
> + * the timeout has elapsed.
> + */
> +void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
> +{
> +	timer_t timer;
> +	struct sigevent sev;
> +	struct sigaction act;
> +	struct itimerspec its;
> +
> +	igt_assert(ns > 0);
> +	if (!spin)
> +		return;
> +
> +	memset(&sev, 0, sizeof(sev));
> +	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
> +	sev.sigev_notify_thread_id = gettid();
> +	sev.sigev_signo = SIGRTMIN + 1;
> +	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
> +	igt_assert(timer > 0);
> +
> +	memset(&act, 0, sizeof(act));
> +	act.sa_sigaction = exit_batch_handler;
> +	act.sa_flags = SA_SIGINFO;
> +	igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0);

Note that we can use multiple signals here and so have multiple spinners
with timeout in parallel now that we save the spinners in a global list.

We should probably check the returned oldact to confirm that the
signal was not in use previously.

> +	memset(&its, 0, sizeof(its));
> +	its.it_value.tv_sec = ns / NSEC_PER_SEC;
> +	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
> +	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
> +
> +	spin->timer = timer;
> +}
> +
> +/**
> + * igt_spin_batch_end:
> + * @spin: spin batch state from igt_spin_batch_new()
> + *
> + * End the recursive batch associated with @spin manually.
> + */
> +void igt_spin_batch_end(igt_spin_t *spin)
> +{
> +	if (!spin)
> +		return;
> +
> +	*spin->batch = MI_BATCH_BUFFER_END;
> +	__sync_synchronize();
> +}
> +
> +/**
> + * igt_spin_batch_free:
> + * @fd: open i915 drm file descriptor
> + * @spin: spin batch state from igt_spin_batch_new()
> + *
> + * This function does the necessary post-processing after starting a recursive
> + * batch with igt_spin_batch_new().
> + */
> +void igt_spin_batch_free(int fd, igt_spin_t *spin)
> +{
> +	if (!spin)
> +		return;
> +
> +	if (spin->timer > 0)
> +		timer_delete(spin->timer);
> +
> +	igt_spin_batch_end(spin);
> +	munmap(spin->batch, bo_size);
> +	gem_close(fd, spin->handle);
> +	free(spin);
> +
> +	num_spin_objects--;

This doesn't handle multiple spin objects correctly. If only we had a
nice circular list struct. We should also contemplate whether we want
this to support threading.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel
  2016-11-25  9:17           ` Chris Wilson
@ 2016-11-25 11:40             ` Abdiel Janulgue
  2016-11-25 11:40               ` [i-g-t PATCH v13 3/6] lib: add igt_dummyload Abdiel Janulgue
                                 ` (2 more replies)
  0 siblings, 3 replies; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-25 11:40 UTC (permalink / raw)
  To: intel-gfx

Since we're going to be using lists for keeping track of spinners
add some generic list helpers from the kernel.

Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 lib/igt_aux.c | 39 +++++++++++++++++++++++++++++++++++++++
 lib/igt_aux.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index b5ae854..28af1d4 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -1265,3 +1265,42 @@ double igt_stop_siglatency(struct igt_mean *result)
 
 	return mean;
 }
+
+static void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+static void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+        prev->next = next;
+}
+
+void INIT_LIST_HEAD(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = NULL;
+	entry->prev = NULL;
+}
+
+bool list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index d4da499..73836d0 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -274,4 +274,50 @@ double igt_stop_siglatency(struct igt_mean *result);
 void igt_set_module_param(const char *name, const char *val);
 void igt_set_module_param_int(const char *name, int val);
 
+/*
+ * This list data structure is a derived from the Linux kerne's list.h
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+void INIT_LIST_HEAD(struct list_head *list);
+
+void list_add(struct list_head *new, struct list_head *head);
+
+void list_del(struct list_head *entry);
+
+bool list_empty(const struct list_head *head);
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE, MEMBER)	__compiler_offsetof(TYPE, MEMBER)
+#else
+#define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)
+#endif
+
+#define container_of(ptr, type, member) ({			\
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+#define list_next_entry(pos, member)				\
+	list_entry((pos)->member.next, typeof(*(pos)), member)
+
+#define list_first_entry(ptr, type, member)	\
+	list_entry((ptr)->next, type, member)
+
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_first_entry(head, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = list_next_entry(pos, member))
+
 #endif /* IGT_AUX_H */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v13 3/6] lib: add igt_dummyload
  2016-11-25 11:40             ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Abdiel Janulgue
@ 2016-11-25 11:40               ` Abdiel Janulgue
  2016-11-25 11:52               ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Chris Wilson
  2016-11-25 11:54               ` Chris Wilson
  2 siblings, 0 replies; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-25 11:40 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

A lot of igt testcases need some GPU workload to make sure a race
window is big enough. Unfortunately having a fixed amount of
workload leads to spurious test failures or overly long runtimes
on some fast/slow platforms. This library contains functionality
to submit GPU workloads that should consume exactly a specific
amount of time.

v10: Split timeout function. Clarify function names (Chris)
v11: From Chris:
     * Add gem_quiescent_gpu exit handler
     * Use gem_bo_busy
     * Skip spin->handle > 0 checks
     * Ensure terminate batch on free
     * Remove igt_spin_batch_wait
     * Remove single-ring limitation
v12: Hook into gem_quiescent_gpu exit handler to idle the GPU if
     the user terminates tests with ^C
v13: Use the kernel's list to handle spiner objects

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: tomeu@tomeuvizoso.net
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/drmtest.c                                      |   3 +
 lib/igt.h                                          |   1 +
 lib/igt_dummyload.c                                | 285 +++++++++++++++++++++
 lib/igt_dummyload.h                                |  49 ++++
 6 files changed, 341 insertions(+)
 create mode 100644 lib/igt_dummyload.c
 create mode 100644 lib/igt_dummyload.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c862f2a..55902ab 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -32,6 +32,7 @@
     <xi:include href="xml/intel_io.xml"/>
     <xi:include href="xml/igt_vc4.xml"/>
     <xi:include href="xml/igt_vgem.xml"/>
+    <xi:include href="xml/igt_dummyload.xml"/>
   </chapter>
   <xi:include href="xml/igt_test_programs.xml"/>
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e8e277b..7fc5ec2 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -75,6 +75,8 @@ lib_source_list =	 	\
 	igt_draw.h		\
 	igt_pm.c		\
 	igt_pm.h		\
+	igt_dummyload.c		\
+	igt_dummyload.h		\
 	uwildmat/uwildmat.h	\
 	uwildmat/uwildmat.c	\
 	$(NULL)
diff --git a/lib/drmtest.c b/lib/drmtest.c
index 44abc7e..be1dc93 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -57,6 +57,7 @@
 #include "config.h"
 #include "intel_reg.h"
 #include "ioctl_wrappers.h"
+#include "igt_dummyload.h"
 
 /**
  * SECTION:drmtest
@@ -159,6 +160,8 @@ void gem_quiescent_gpu(int fd)
 	struct drm_i915_gem_exec_object2 obj;
 	unsigned ring;
 
+	igt_terminate_spin_batches();
+
 	memset(&obj, 0, sizeof(obj));
 	obj.handle = gem_create(fd, 4096);
 	gem_write(fd, obj.handle, 0, &bbe, sizeof(&bbe));
diff --git a/lib/igt.h b/lib/igt.h
index d751f24..a0028d5 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -32,6 +32,7 @@
 #include "igt_core.h"
 #include "igt_debugfs.h"
 #include "igt_draw.h"
+#include "igt_dummyload.h"
 #include "igt_fb.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
new file mode 100644
index 0000000..0d6e27a
--- /dev/null
+++ b/lib/igt_dummyload.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "igt.h"
+#include "igt_dummyload.h"
+#include <time.h>
+#include <signal.h>
+#include <sys/syscall.h>
+
+/**
+ * SECTION:igt_dummyload
+ * @short_description: Library for submitting GPU workloads
+ * @title: Dummyload
+ * @include: igt.h
+ *
+ * A lot of igt testcases need some GPU workload to make sure a race window is
+ * big enough. Unfortunately having a fixed amount of workload leads to
+ * spurious test failures or overly long runtimes on some fast/slow platforms.
+ * This library contains functionality to submit GPU workloads that should
+ * consume exactly a specific amount of time.
+ */
+
+#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
+#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
+
+#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
+
+static const int bo_size = 4096;
+
+static void
+fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
+	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
+{
+	memset(obj, 0, sizeof(*obj));
+	obj->handle = gem_handle;
+	obj->relocation_count = count;
+	obj->relocs_ptr = (uintptr_t)relocs;
+}
+
+static void
+fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+	   uint32_t gem_handle, uint32_t offset,
+	   uint32_t read_domains, uint32_t write_domains)
+{
+	reloc->target_handle = gem_handle;
+	reloc->delta = 0;
+	reloc->offset = offset * sizeof(uint32_t);
+	reloc->presumed_offset = 0;
+	reloc->read_domains = read_domains;
+	reloc->write_domain = write_domains;
+}
+
+/*
+ * Needs to be global. Signal handlers don't accept arguments
+ */
+static uint32_t *batch;
+
+static uint32_t emit_recursive_batch(int fd, int engine,
+				     unsigned int dep_handle)
+{
+	const int gen = intel_gen(intel_get_drm_devid(fd));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry relocs[2];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	unsigned int engines[16];
+	unsigned int nengine, handle;
+	int i = 0, reloc_count = 0, buf_count = 0;
+
+	buf_count = 0;
+	nengine = 0;
+	if (engine < 0) {
+		for_each_engine(fd, engine)
+			if (engine)
+				engines[nengine++] = engine;
+	} else {
+		gem_require_ring(fd, engine);
+		engines[nengine++] = engine;
+	}
+	igt_require(nengine);
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	memset(obj, 0, sizeof(obj));
+	memset(relocs, 0, sizeof(relocs));
+
+	execbuf.buffers_ptr = (uintptr_t) obj;
+	handle = gem_create(fd, bo_size);
+	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
+	igt_assert(batch);
+	gem_set_domain(fd, handle,
+			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+	if (dep_handle > 0) {
+		/* dummy write to dependency */
+		fill_object(&obj[buf_count], dep_handle, NULL, 0);
+		buf_count++;
+
+		fill_reloc(&relocs[reloc_count], dep_handle, 256,
+			   I915_GEM_DOMAIN_RENDER,
+			   I915_GEM_DOMAIN_RENDER);
+		reloc_count++;
+	}
+
+	if (gen >= 8) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		batch[i++] = 0;
+	} else if (gen >= 6) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+	} else {
+		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
+			((gen < 4) ? 1 : 0);
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		if (gen < 4)
+			relocs[reloc_count].delta = 1;
+	}
+	reloc_count++;
+
+	fill_object(&obj[buf_count], handle, relocs, reloc_count);
+	buf_count++;
+
+	for (i = 0; i < nengine; i++) {
+		execbuf.flags = engines[i];
+		execbuf.flags &= ~ENGINE_MASK;
+		execbuf.buffer_count = buf_count;
+		gem_execbuf(fd, &execbuf);
+	}
+
+	return handle;
+}
+
+static void exit_batch_handler(int sig, siginfo_t *info, void *spin)
+{
+	*batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+LIST_HEAD(spin_objects);
+
+void igt_terminate_spin_batches(void)
+{
+	struct igt_spin *iter = NULL;
+
+	list_for_each_entry(iter, &spin_objects, link)
+		igt_spin_batch_end(iter);
+}
+
+/**
+ * igt_spin_batch_new:
+ * @fd: open i915 drm file descriptor
+ * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
+ *          than 0, execute on all available rings.
+ * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
+ *              relocation entry to this buffer within the batch.
+ *
+ * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
+ * contains the batch's handle that can be waited upon. The returned structure
+ * must be passed to igt_spin_batch_free() for post-processing.
+ *
+ * Returns:
+ * Structure with helper internal state for igt_spin_batch_free().
+ */
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle)
+{
+	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
+	uint32_t handle = emit_recursive_batch(fd, engine, dep_handle);
+
+	igt_assert(gem_bo_busy(fd, handle));
+	spin->handle = handle;
+	spin->batch = batch;
+	spin->timer = NULL;
+	INIT_LIST_HEAD(&spin->link);
+	list_add(&spin->link, &spin_objects);
+
+	return spin;
+}
+
+/**
+ * igt_spin_batch_set_timeout:
+ * @spin: spin batch state from igt_spin_batch_new()
+ * @ns: amount of time in nanoseconds the batch continues to execute
+ *      before finishing.
+ *
+ * Specify a timeout. This ends the recursive batch associated with @spin after
+ * the timeout has elapsed.
+ */
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
+{
+	timer_t timer;
+	struct sigevent sev;
+	struct sigaction act;
+	struct itimerspec its;
+
+	igt_assert(ns > 0);
+	if (!spin)
+		return;
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+	sev.sigev_notify_thread_id = gettid();
+	sev.sigev_signo = SIGRTMIN + 1;
+	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
+	igt_assert(timer > 0);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = exit_batch_handler;
+	act.sa_flags = SA_SIGINFO;
+	igt_assert(sigaction(SIGRTMIN + 1, &act, NULL) == 0);
+
+	memset(&its, 0, sizeof(its));
+	its.it_value.tv_sec = ns / NSEC_PER_SEC;
+	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
+	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
+
+	spin->timer = timer;
+}
+
+/**
+ * igt_spin_batch_end:
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * End the recursive batch associated with @spin manually.
+ */
+void igt_spin_batch_end(igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	*spin->batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+/**
+ * igt_spin_batch_free:
+ * @fd: open i915 drm file descriptor
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * This function does the necessary post-processing after starting a recursive
+ * batch with igt_spin_batch_new().
+ */
+void igt_spin_batch_free(int fd, igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	if (spin->timer > 0)
+		timer_delete(spin->timer);
+
+	igt_spin_batch_end(spin);
+	munmap(spin->batch, bo_size);
+	gem_close(fd, spin->handle);
+	list_del(&spin->link);
+	free(spin);
+}
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
new file mode 100644
index 0000000..5897765
--- /dev/null
+++ b/lib/igt_dummyload.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#ifndef __IGT_DUMMYLOAD_H__
+#define __IGT_DUMMYLOAD_H__
+
+#include "igt_aux.h"
+
+typedef struct igt_spin {
+	unsigned int handle;
+	uint32_t *batch;
+	timer_t timer;
+	struct list_head link;
+} igt_spin_t;
+
+
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle);
+
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns);
+
+void igt_spin_batch_end(igt_spin_t *spin);
+
+void igt_spin_batch_free(int fd, igt_spin_t *spin);
+
+void igt_terminate_spin_batches(void);
+
+#endif /* __IGT_DUMMYLOAD_H__ */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel
  2016-11-25 11:40             ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Abdiel Janulgue
  2016-11-25 11:40               ` [i-g-t PATCH v13 3/6] lib: add igt_dummyload Abdiel Janulgue
@ 2016-11-25 11:52               ` Chris Wilson
  2016-11-25 11:54               ` Chris Wilson
  2 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2016-11-25 11:52 UTC (permalink / raw)
  To: Abdiel Janulgue; +Cc: intel-gfx

On Fri, Nov 25, 2016 at 01:40:31PM +0200, Abdiel Janulgue wrote:
> Since we're going to be using lists for keeping track of spinners
> add some generic list helpers from the kernel.
> 
> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
> ---
>  lib/igt_aux.c | 39 +++++++++++++++++++++++++++++++++++++++
>  lib/igt_aux.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 85 insertions(+)
> 
> diff --git a/lib/igt_aux.c b/lib/igt_aux.c
> index b5ae854..28af1d4 100644
> --- a/lib/igt_aux.c
> +++ b/lib/igt_aux.c
> @@ -1265,3 +1265,42 @@ double igt_stop_siglatency(struct igt_mean *result)
>  
>  	return mean;
>  }
> +
> +static void __list_add(struct list_head *new,
> +			      struct list_head *prev,
> +			      struct list_head *next)
> +{
> +	next->prev = new;
> +	new->next = next;
> +	new->prev = prev;
> +	prev->next = new;
> +}
> +
> +static void __list_del(struct list_head * prev, struct list_head * next)
> +{
> +	next->prev = prev;
> +        prev->next = next;
> +}
> +
> +void INIT_LIST_HEAD(struct list_head *list)
> +{
> +	list->next = list;
> +	list->prev = list;
> +}
> +
> +void list_add(struct list_head *new, struct list_head *head)
> +{
> +	__list_add(new, head, head->next);
> +}
> +
> +void list_del(struct list_head *entry)
> +{
> +	__list_del(entry->prev, entry->next);
> +	entry->next = NULL;
> +	entry->prev = NULL;

list_del in the absence of list_del_init() should reinit the list.

> +}
> +
> +bool list_empty(const struct list_head *head)
> +{
> +	return head->next == head;
> +}
> diff --git a/lib/igt_aux.h b/lib/igt_aux.h
> index d4da499..73836d0 100644
> --- a/lib/igt_aux.h
> +++ b/lib/igt_aux.h
> @@ -274,4 +274,50 @@ double igt_stop_siglatency(struct igt_mean *result);
>  void igt_set_module_param(const char *name, const char *val);
>  void igt_set_module_param_int(const char *name, int val);
>  
> +/*
> + * This list data structure is a derived from the Linux kerne's list.h
> + */
> +
> +struct list_head {
> +	struct list_head *next, *prev;
> +};
> +
> +#define LIST_HEAD_INIT(name) { &(name), &(name) }
> +
> +#define LIST_HEAD(name) \
> +	struct list_head name = LIST_HEAD_INIT(name)
> +
> +void INIT_LIST_HEAD(struct list_head *list);
> +
> +void list_add(struct list_head *new, struct list_head *head);
> +
> +void list_del(struct list_head *entry);
> +
> +bool list_empty(const struct list_head *head);
> +
> +#undef offsetof

#ifndef offsetof

> +#ifdef __compiler_offsetof
> +#define offsetof(TYPE, MEMBER)	__compiler_offsetof(TYPE, MEMBER)
> +#else
> +#define offsetof(TYPE, MEMBER)	((size_t)&((TYPE *)0)->MEMBER)
> +#endif
> +
> +#define container_of(ptr, type, member) ({			\
> +	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
> +	(type *)( (char *)__mptr - offsetof(type,member) );})
> +
> +#define list_entry(ptr, type, member) \
> +	container_of(ptr, type, member)
> +
> +#define list_next_entry(pos, member)				\
> +	list_entry((pos)->member.next, typeof(*(pos)), member)
> +
> +#define list_first_entry(ptr, type, member)	\
> +	list_entry((ptr)->next, type, member)
> +
> +#define list_for_each_entry(pos, head, member)				\
> +	for (pos = list_first_entry(head, typeof(*pos), member);	\
> +	     &pos->member != (head);					\
> +	     pos = list_next_entry(pos, member))

Since we can use c99, there is an argument for using mesa's util/list.h
instead (nicer loop iteration). Plus we don't have to wrangle over
copyright clauses as much.
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel
  2016-11-25 11:40             ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Abdiel Janulgue
  2016-11-25 11:40               ` [i-g-t PATCH v13 3/6] lib: add igt_dummyload Abdiel Janulgue
  2016-11-25 11:52               ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Chris Wilson
@ 2016-11-25 11:54               ` Chris Wilson
  2016-11-25 14:41                 ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from wayland Abdiel Janulgue
  2 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2016-11-25 11:54 UTC (permalink / raw)
  To: Abdiel Janulgue; +Cc: intel-gfx

On Fri, Nov 25, 2016 at 01:40:31PM +0200, Abdiel Janulgue wrote:
> Since we're going to be using lists for keeping track of spinners
> add some generic list helpers from the kernel.

I should also say look at the chamelium patches so that we only have to
import a circular list once (i.e. make sure the interface is complete
enough for other patches in flight).
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [i-g-t PATCH 2/6] igt_aux: Add some list helpers from wayland
  2016-11-25 11:54               ` Chris Wilson
@ 2016-11-25 14:41                 ` Abdiel Janulgue
  2016-11-25 14:41                   ` [i-g-t PATCH v14 3/6] lib: add igt_dummyload Abdiel Janulgue
  0 siblings, 1 reply; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-25 14:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Lyude

From: Lyude <lyude@redhat.com>

Since we're going to be using lists for keeping track of EDIDs we've
allocated on the chamelium, add some generic list helpers from the
wayland project.

Signed-off-by: Lyude <lyude@redhat.com>

Changes since v1:
- Rename list helpers to be more like those from the Linux kernel
---
 lib/igt_aux.c | 27 +++++++++++++++++++++++++++
 lib/igt_aux.h | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index b5ae854..56bddd6 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -1265,3 +1265,30 @@ double igt_stop_siglatency(struct igt_mean *result)
 
 	return mean;
 }
+
+void igt_list_init(struct igt_list *igt_list)
+{
+	igt_list->prev = igt_list;
+	igt_list->next = igt_list;
+}
+
+void igt_list_add(struct igt_list *igt_list, struct igt_list *elm)
+{
+	elm->prev = igt_list;
+	elm->next = igt_list->next;
+	igt_list->next = elm;
+	elm->next->prev = elm;
+}
+
+void igt_list_del(struct igt_list *elm)
+{
+	elm->prev->next = elm->next;
+	elm->next->prev = elm->prev;
+	elm->next = NULL;
+	elm->prev = NULL;
+}
+
+bool igt_list_empty(const struct igt_list *igt_list)
+{
+	return igt_list->next == igt_list;
+}
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index d4da499..9d1c44a 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -274,4 +274,42 @@ double igt_stop_siglatency(struct igt_mean *result);
 void igt_set_module_param(const char *name, const char *val);
 void igt_set_module_param_int(const char *name, int val);
 
+/*
+ * This list data structure is a verbatim copy from wayland-util.h from the
+ * Wayland project; except that wl_ prefix has been removed.
+ */
+
+struct igt_list {
+	struct igt_list *prev;
+	struct igt_list *next;
+};
+
+void igt_list_init(struct igt_list *list);
+void igt_list_add(struct igt_list *list, struct igt_list *elm);
+void igt_list_del(struct igt_list *elm);
+bool igt_list_empty(const struct igt_list *list);
+
+#ifdef __GNUC__
+#define container_of(ptr, sample, member)				\
+	(__typeof__(sample))((char *)(ptr)	-			\
+		 ((char *)&(sample)->member - (char *)(sample)))
+#else
+#define container_of(ptr, sample, member)				\
+	(void *)((char *)(ptr)	-				        \
+		 ((char *)&(sample)->member - (char *)(sample)))
+#endif
+
+#define igt_list_for_each(pos, head, member)				\
+	for (pos = 0, pos = container_of((head)->next, pos, member);	\
+	     &pos->member != (head);					\
+	     pos = container_of(pos->member.next, pos, member))
+
+#define igt_list_for_each_safe(pos, tmp, head, member)			\
+	for (pos = 0, tmp = 0, 						\
+	     pos = container_of((head)->next, pos, member),		\
+	     tmp = container_of((pos)->member.next, tmp, member);	\
+	     &pos->member != (head);					\
+	     pos = tmp,							\
+	     tmp = container_of(pos->member.next, tmp, member))
+
 #endif /* IGT_AUX_H */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v14 3/6] lib: add igt_dummyload
  2016-11-25 14:41                 ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from wayland Abdiel Janulgue
@ 2016-11-25 14:41                   ` Abdiel Janulgue
  2016-11-25 15:19                     ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-25 14:41 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

A lot of igt testcases need some GPU workload to make sure a race
window is big enough. Unfortunately having a fixed amount of
workload leads to spurious test failures or overly long runtimes
on some fast/slow platforms. This library contains functionality
to submit GPU workloads that should consume exactly a specific
amount of time.

v10: Split timeout function. Clarify function names (Chris)
v11: From Chris:
     * Add gem_quiescent_gpu exit handler
     * Use gem_bo_busy
     * Skip spin->handle > 0 checks
     * Ensure terminate batch on free
     * Remove igt_spin_batch_wait
     * Remove single-ring limitation
v12: Hook into gem_quiescent_gpu exit handler to idle the GPU if
     the user terminates tests with ^C
v13: Use the kernel's list to handle spinner objects
v14: Use multiple signals, cycle available signals from
     SIGRTMIN to SIGRTMAX. Reuse list definition from Chamelium
     patches.

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: tomeu@tomeuvizoso.net
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/drmtest.c                                      |   3 +
 lib/igt.h                                          |   1 +
 lib/igt_dummyload.c                                | 300 +++++++++++++++++++++
 lib/igt_dummyload.h                                |  49 ++++
 6 files changed, 356 insertions(+)
 create mode 100644 lib/igt_dummyload.c
 create mode 100644 lib/igt_dummyload.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c862f2a..55902ab 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -32,6 +32,7 @@
     <xi:include href="xml/intel_io.xml"/>
     <xi:include href="xml/igt_vc4.xml"/>
     <xi:include href="xml/igt_vgem.xml"/>
+    <xi:include href="xml/igt_dummyload.xml"/>
   </chapter>
   <xi:include href="xml/igt_test_programs.xml"/>
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e8e277b..7fc5ec2 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -75,6 +75,8 @@ lib_source_list =	 	\
 	igt_draw.h		\
 	igt_pm.c		\
 	igt_pm.h		\
+	igt_dummyload.c		\
+	igt_dummyload.h		\
 	uwildmat/uwildmat.h	\
 	uwildmat/uwildmat.c	\
 	$(NULL)
diff --git a/lib/drmtest.c b/lib/drmtest.c
index 44abc7e..be1dc93 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -57,6 +57,7 @@
 #include "config.h"
 #include "intel_reg.h"
 #include "ioctl_wrappers.h"
+#include "igt_dummyload.h"
 
 /**
  * SECTION:drmtest
@@ -159,6 +160,8 @@ void gem_quiescent_gpu(int fd)
 	struct drm_i915_gem_exec_object2 obj;
 	unsigned ring;
 
+	igt_terminate_spin_batches();
+
 	memset(&obj, 0, sizeof(obj));
 	obj.handle = gem_create(fd, 4096);
 	gem_write(fd, obj.handle, 0, &bbe, sizeof(&bbe));
diff --git a/lib/igt.h b/lib/igt.h
index d751f24..a0028d5 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -32,6 +32,7 @@
 #include "igt_core.h"
 #include "igt_debugfs.h"
 #include "igt_draw.h"
+#include "igt_dummyload.h"
 #include "igt_fb.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
new file mode 100644
index 0000000..d388f6e
--- /dev/null
+++ b/lib/igt_dummyload.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "igt.h"
+#include "igt_dummyload.h"
+#include <time.h>
+#include <signal.h>
+#include <sys/syscall.h>
+
+/**
+ * SECTION:igt_dummyload
+ * @short_description: Library for submitting GPU workloads
+ * @title: Dummyload
+ * @include: igt.h
+ *
+ * A lot of igt testcases need some GPU workload to make sure a race window is
+ * big enough. Unfortunately having a fixed amount of workload leads to
+ * spurious test failures or overly long runtimes on some fast/slow platforms.
+ * This library contains functionality to submit GPU workloads that should
+ * consume exactly a specific amount of time.
+ */
+
+#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
+#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
+
+#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
+
+static const int bo_size = 4096;
+static struct igt_list spin_list = { &(spin_list), &(spin_list) };
+static int spin_object_timer_id = 0;
+
+static void
+fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
+	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
+{
+	memset(obj, 0, sizeof(*obj));
+	obj->handle = gem_handle;
+	obj->relocation_count = count;
+	obj->relocs_ptr = (uintptr_t)relocs;
+}
+
+static void
+fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+	   uint32_t gem_handle, uint32_t offset,
+	   uint32_t read_domains, uint32_t write_domains)
+{
+	reloc->target_handle = gem_handle;
+	reloc->delta = 0;
+	reloc->offset = offset * sizeof(uint32_t);
+	reloc->presumed_offset = 0;
+	reloc->read_domains = read_domains;
+	reloc->write_domain = write_domains;
+}
+
+/*
+ * Needs to be global. Signal handlers don't accept arguments
+ */
+static uint32_t *batch;
+
+static uint32_t emit_recursive_batch(int fd, int engine,
+				     unsigned int dep_handle)
+{
+	const int gen = intel_gen(intel_get_drm_devid(fd));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry relocs[2];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	unsigned int engines[16];
+	unsigned int nengine, handle;
+	int i = 0, reloc_count = 0, buf_count = 0;
+
+	buf_count = 0;
+	nengine = 0;
+	if (engine < 0) {
+		for_each_engine(fd, engine)
+			if (engine)
+				engines[nengine++] = engine;
+	} else {
+		gem_require_ring(fd, engine);
+		engines[nengine++] = engine;
+	}
+	igt_require(nengine);
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	memset(obj, 0, sizeof(obj));
+	memset(relocs, 0, sizeof(relocs));
+
+	execbuf.buffers_ptr = (uintptr_t) obj;
+	handle = gem_create(fd, bo_size);
+	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
+	igt_assert(batch);
+	gem_set_domain(fd, handle,
+			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+	if (dep_handle > 0) {
+		/* dummy write to dependency */
+		fill_object(&obj[buf_count], dep_handle, NULL, 0);
+		buf_count++;
+
+		fill_reloc(&relocs[reloc_count], dep_handle, 256,
+			   I915_GEM_DOMAIN_RENDER,
+			   I915_GEM_DOMAIN_RENDER);
+		reloc_count++;
+	}
+
+	if (gen >= 8) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		batch[i++] = 0;
+	} else if (gen >= 6) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+	} else {
+		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
+			((gen < 4) ? 1 : 0);
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		if (gen < 4)
+			relocs[reloc_count].delta = 1;
+	}
+	reloc_count++;
+
+	fill_object(&obj[buf_count], handle, relocs, reloc_count);
+	buf_count++;
+
+	for (i = 0; i < nengine; i++) {
+		execbuf.flags = engines[i];
+		execbuf.flags &= ~ENGINE_MASK;
+		execbuf.buffer_count = buf_count;
+		gem_execbuf(fd, &execbuf);
+	}
+
+	return handle;
+}
+
+static void exit_batch_handler(int sig, siginfo_t *info, void *spin)
+{
+	struct sigaction act;
+
+	*batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = SIG_DFL;
+	igt_assert(sigaction(info->si_signo, &act, NULL) == 0);
+}
+
+
+void igt_terminate_spin_batches(void)
+{
+	struct igt_spin *iter, *tmp;
+
+	igt_list_for_each_safe(iter, tmp, &spin_list, link)
+		igt_spin_batch_end(iter);
+}
+
+/**
+ * igt_spin_batch_new:
+ * @fd: open i915 drm file descriptor
+ * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
+ *          than 0, execute on all available rings.
+ * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
+ *              relocation entry to this buffer within the batch.
+ *
+ * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
+ * contains the batch's handle that can be waited upon. The returned structure
+ * must be passed to igt_spin_batch_free() for post-processing.
+ *
+ * Returns:
+ * Structure with helper internal state for igt_spin_batch_free().
+ */
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle)
+{
+	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
+	uint32_t handle = emit_recursive_batch(fd, engine, dep_handle);
+
+	igt_assert(gem_bo_busy(fd, handle));
+	igt_list_init(&spin->link);
+	spin->handle = handle;
+	spin->batch = batch;
+	spin->timer = NULL;
+	igt_list_add(&spin_list, &spin->link);
+
+	return spin;
+}
+
+/**
+ * igt_spin_batch_set_timeout:
+ * @spin: spin batch state from igt_spin_batch_new()
+ * @ns: amount of time in nanoseconds the batch continues to execute
+ *      before finishing.
+ *
+ * Specify a timeout. This ends the recursive batch associated with @spin after
+ * the timeout has elapsed.
+ */
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
+{
+	timer_t timer;
+	struct sigevent sev;
+	struct sigaction act, oldact;
+	struct itimerspec its;
+	int signum;
+
+	igt_assert(ns > 0);
+	if (!spin)
+		return;
+
+	if (spin_object_timer_id > SIGRTMAX - 1)
+		spin_object_timer_id = 0;
+	signum = SIGRTMIN + spin_object_timer_id++;
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+	sev.sigev_notify_thread_id = gettid();
+	sev.sigev_signo = signum;
+	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
+	igt_assert(timer > 0);
+
+	memset(&oldact, 0, sizeof(oldact));
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = exit_batch_handler;
+	act.sa_flags = SA_SIGINFO;
+	igt_assert(sigaction(signum, &act, &oldact) == 0);
+	igt_assert(oldact.sa_sigaction == NULL);
+
+	memset(&its, 0, sizeof(its));
+	its.it_value.tv_sec = ns / NSEC_PER_SEC;
+	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
+	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
+
+	spin->timer = timer;
+}
+
+/**
+ * igt_spin_batch_end:
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * End the recursive batch associated with @spin manually.
+ */
+void igt_spin_batch_end(igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	*spin->batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+/**
+ * igt_spin_batch_free:
+ * @fd: open i915 drm file descriptor
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * This function does the necessary post-processing after starting a recursive
+ * batch with igt_spin_batch_new().
+ */
+void igt_spin_batch_free(int fd, igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	if (spin->timer > 0)
+		timer_delete(spin->timer);
+
+	igt_spin_batch_end(spin);
+	munmap(spin->batch, bo_size);
+	gem_close(fd, spin->handle);
+	igt_list_del(&spin->link);
+	free(spin);
+}
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
new file mode 100644
index 0000000..b250f8f
--- /dev/null
+++ b/lib/igt_dummyload.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#ifndef __IGT_DUMMYLOAD_H__
+#define __IGT_DUMMYLOAD_H__
+
+#include "igt_aux.h"
+
+typedef struct igt_spin {
+	unsigned int handle;
+	uint32_t *batch;
+	timer_t timer;
+	struct igt_list link;
+} igt_spin_t;
+
+
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle);
+
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns);
+
+void igt_spin_batch_end(igt_spin_t *spin);
+
+void igt_spin_batch_free(int fd, igt_spin_t *spin);
+
+void igt_terminate_spin_batches(void);
+
+#endif /* __IGT_DUMMYLOAD_H__ */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [i-g-t PATCH v14 3/6] lib: add igt_dummyload
  2016-11-25 14:41                   ` [i-g-t PATCH v14 3/6] lib: add igt_dummyload Abdiel Janulgue
@ 2016-11-25 15:19                     ` Chris Wilson
  2016-11-28  7:37                       ` [i-g-t PATCH v15 " Abdiel Janulgue
  0 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2016-11-25 15:19 UTC (permalink / raw)
  To: Abdiel Janulgue; +Cc: Daniel Vetter, intel-gfx

On Fri, Nov 25, 2016 at 04:41:14PM +0200, Abdiel Janulgue wrote:
> A lot of igt testcases need some GPU workload to make sure a race
> window is big enough. Unfortunately having a fixed amount of
> workload leads to spurious test failures or overly long runtimes
> on some fast/slow platforms. This library contains functionality
> to submit GPU workloads that should consume exactly a specific
> amount of time.
> 
> v10: Split timeout function. Clarify function names (Chris)
> v11: From Chris:
>      * Add gem_quiescent_gpu exit handler
>      * Use gem_bo_busy
>      * Skip spin->handle > 0 checks
>      * Ensure terminate batch on free
>      * Remove igt_spin_batch_wait
>      * Remove single-ring limitation
> v12: Hook into gem_quiescent_gpu exit handler to idle the GPU if
>      the user terminates tests with ^C
> v13: Use the kernel's list to handle spinner objects
> v14: Use multiple signals, cycle available signals from
>      SIGRTMIN to SIGRTMAX. Reuse list definition from Chamelium
>      patches.
> 
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: tomeu@tomeuvizoso.net
> Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
> Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
> ---
>  .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
>  lib/Makefile.sources                               |   2 +
>  lib/drmtest.c                                      |   3 +
>  lib/igt.h                                          |   1 +
>  lib/igt_dummyload.c                                | 300 +++++++++++++++++++++
>  lib/igt_dummyload.h                                |  49 ++++
>  6 files changed, 356 insertions(+)
>  create mode 100644 lib/igt_dummyload.c
>  create mode 100644 lib/igt_dummyload.h
> 
> diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> index c862f2a..55902ab 100644
> --- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> +++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
> @@ -32,6 +32,7 @@
>      <xi:include href="xml/intel_io.xml"/>
>      <xi:include href="xml/igt_vc4.xml"/>
>      <xi:include href="xml/igt_vgem.xml"/>
> +    <xi:include href="xml/igt_dummyload.xml"/>
>    </chapter>
>    <xi:include href="xml/igt_test_programs.xml"/>
>  
> diff --git a/lib/Makefile.sources b/lib/Makefile.sources
> index e8e277b..7fc5ec2 100644
> --- a/lib/Makefile.sources
> +++ b/lib/Makefile.sources
> @@ -75,6 +75,8 @@ lib_source_list =	 	\
>  	igt_draw.h		\
>  	igt_pm.c		\
>  	igt_pm.h		\
> +	igt_dummyload.c		\
> +	igt_dummyload.h		\
>  	uwildmat/uwildmat.h	\
>  	uwildmat/uwildmat.c	\
>  	$(NULL)
> diff --git a/lib/drmtest.c b/lib/drmtest.c
> index 44abc7e..be1dc93 100644
> --- a/lib/drmtest.c
> +++ b/lib/drmtest.c
> @@ -57,6 +57,7 @@
>  #include "config.h"
>  #include "intel_reg.h"
>  #include "ioctl_wrappers.h"
> +#include "igt_dummyload.h"
>  
>  /**
>   * SECTION:drmtest
> @@ -159,6 +160,8 @@ void gem_quiescent_gpu(int fd)
>  	struct drm_i915_gem_exec_object2 obj;
>  	unsigned ring;
>  
> +	igt_terminate_spin_batches();
> +
>  	memset(&obj, 0, sizeof(obj));
>  	obj.handle = gem_create(fd, 4096);
>  	gem_write(fd, obj.handle, 0, &bbe, sizeof(&bbe));
> diff --git a/lib/igt.h b/lib/igt.h
> index d751f24..a0028d5 100644
> --- a/lib/igt.h
> +++ b/lib/igt.h
> @@ -32,6 +32,7 @@
>  #include "igt_core.h"
>  #include "igt_debugfs.h"
>  #include "igt_draw.h"
> +#include "igt_dummyload.h"
>  #include "igt_fb.h"
>  #include "igt_gt.h"
>  #include "igt_kms.h"
> diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
> new file mode 100644
> index 0000000..d388f6e
> --- /dev/null
> +++ b/lib/igt_dummyload.c
> @@ -0,0 +1,300 @@
> +/*
> + * Copyright © 2016 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.
> + *
> + */
> +
> +#include "igt.h"
> +#include "igt_dummyload.h"
> +#include <time.h>
> +#include <signal.h>
> +#include <sys/syscall.h>
> +
> +/**
> + * SECTION:igt_dummyload
> + * @short_description: Library for submitting GPU workloads
> + * @title: Dummyload
> + * @include: igt.h
> + *
> + * A lot of igt testcases need some GPU workload to make sure a race window is
> + * big enough. Unfortunately having a fixed amount of workload leads to
> + * spurious test failures or overly long runtimes on some fast/slow platforms.
> + * This library contains functionality to submit GPU workloads that should
> + * consume exactly a specific amount of time.
> + */
> +
> +#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
> +#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
> +
> +#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
> +
> +static const int bo_size = 4096;
> +static struct igt_list spin_list = { &(spin_list), &(spin_list) };
> +static int spin_object_timer_id = 0;
> +
> +static void
> +fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
> +	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
> +{
> +	memset(obj, 0, sizeof(*obj));
> +	obj->handle = gem_handle;
> +	obj->relocation_count = count;
> +	obj->relocs_ptr = (uintptr_t)relocs;
> +}
> +
> +static void
> +fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
> +	   uint32_t gem_handle, uint32_t offset,
> +	   uint32_t read_domains, uint32_t write_domains)
> +{
> +	reloc->target_handle = gem_handle;
> +	reloc->delta = 0;
> +	reloc->offset = offset * sizeof(uint32_t);
> +	reloc->presumed_offset = 0;
> +	reloc->read_domains = read_domains;
> +	reloc->write_domain = write_domains;
> +}
> +
> +/*
> + * Needs to be global. Signal handlers don't accept arguments
> + */
> +static uint32_t *batch;
> +
> +static uint32_t emit_recursive_batch(int fd, int engine,
> +				     unsigned int dep_handle)
> +{
> +	const int gen = intel_gen(intel_get_drm_devid(fd));
> +	struct drm_i915_gem_exec_object2 obj[2];
> +	struct drm_i915_gem_relocation_entry relocs[2];
> +	struct drm_i915_gem_execbuffer2 execbuf;
> +	unsigned int engines[16];
> +	unsigned int nengine, handle;
> +	int i = 0, reloc_count = 0, buf_count = 0;
> +
> +	buf_count = 0;
> +	nengine = 0;
> +	if (engine < 0) {
> +		for_each_engine(fd, engine)
> +			if (engine)
> +				engines[nengine++] = engine;
> +	} else {
> +		gem_require_ring(fd, engine);
> +		engines[nengine++] = engine;
> +	}
> +	igt_require(nengine);
> +
> +	memset(&execbuf, 0, sizeof(execbuf));
> +	memset(obj, 0, sizeof(obj));
> +	memset(relocs, 0, sizeof(relocs));
> +
> +	execbuf.buffers_ptr = (uintptr_t) obj;
> +	handle = gem_create(fd, bo_size);
> +	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
> +	igt_assert(batch);
> +	gem_set_domain(fd, handle,
> +			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
> +
> +	if (dep_handle > 0) {
> +		/* dummy write to dependency */
> +		fill_object(&obj[buf_count], dep_handle, NULL, 0);
> +		buf_count++;
> +
> +		fill_reloc(&relocs[reloc_count], dep_handle, 256,
> +			   I915_GEM_DOMAIN_RENDER,
> +			   I915_GEM_DOMAIN_RENDER);
> +		reloc_count++;
> +	}
> +
> +	if (gen >= 8) {
> +		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
> +		/* recurse */
> +		fill_reloc(&relocs[reloc_count], handle, i,
> +			   I915_GEM_DOMAIN_COMMAND, 0);
> +		batch[i++] = 0;
> +		batch[i++] = 0;
> +	} else if (gen >= 6) {
> +		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
> +		/* recurse */
> +		fill_reloc(&relocs[reloc_count], handle, i,
> +			   I915_GEM_DOMAIN_COMMAND, 0);
> +		batch[i++] = 0;
> +	} else {
> +		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
> +			((gen < 4) ? 1 : 0);
> +		/* recurse */
> +		fill_reloc(&relocs[reloc_count], handle, i,
> +			   I915_GEM_DOMAIN_COMMAND, 0);
> +		batch[i++] = 0;
> +		if (gen < 4)
> +			relocs[reloc_count].delta = 1;
> +	}
> +	reloc_count++;
> +
> +	fill_object(&obj[buf_count], handle, relocs, reloc_count);
> +	buf_count++;
> +
> +	for (i = 0; i < nengine; i++) {
> +		execbuf.flags = engines[i];
> +		execbuf.flags &= ~ENGINE_MASK;
> +		execbuf.buffer_count = buf_count;
> +		gem_execbuf(fd, &execbuf);
> +	}
> +
> +	return handle;
> +}
> +
> +static void exit_batch_handler(int sig, siginfo_t *info, void *spin)
> +{
> +	struct sigaction act;
> +
> +	*batch = MI_BATCH_BUFFER_END;

But we now have multiple signals, shouldn't you walk the list of active
spinners to see which matches this sig?

And then we can rid ourselves of the global batch, which is then moved
to spinner.

> +	__sync_synchronize();
> +
> +	memset(&act, 0, sizeof(act));
> +	act.sa_handler = SIG_DFL;
> +	igt_assert(sigaction(info->si_signo, &act, NULL) == 0);
> +}

> +void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
> +{
> +	timer_t timer;
> +	struct sigevent sev;
> +	struct sigaction act, oldact;
> +	struct itimerspec its;
> +	int signum;
> +
> +	igt_assert(ns > 0);
> +	if (!spin)
> +		return;
> +
> +	if (spin_object_timer_id > SIGRTMAX - 1)
> +		spin_object_timer_id = 0;
> +	signum = SIGRTMIN + spin_object_timer_id++;

Ah, so we need to keep SIGRTMIN clear for the interruptible helper, and
really that should be SIGRTMIN+1 as valgrind wants SIGRTMIN for itself.
Anyway this needs to be a preincrement and a check for

static int spin_signo = SIGRTMIN;

if (spin_signo == SIGRTMAX)
	spin_signo = SIGRTMIN;

spin->signo = ++spin_signo;

> +
> +	memset(&sev, 0, sizeof(sev));
> +	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
> +	sev.sigev_notify_thread_id = gettid();
> +	sev.sigev_signo = signum;

sev.sigev_signo = spin->signo;

-- 
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [i-g-t PATCH v15 3/6] lib: add igt_dummyload
  2016-11-25 15:19                     ` Chris Wilson
@ 2016-11-28  7:37                       ` Abdiel Janulgue
  0 siblings, 0 replies; 20+ messages in thread
From: Abdiel Janulgue @ 2016-11-28  7:37 UTC (permalink / raw)
  To: intel-gfx; +Cc: Daniel Vetter

A lot of igt testcases need some GPU workload to make sure a race
window is big enough. Unfortunately having a fixed amount of
workload leads to spurious test failures or overly long runtimes
on some fast/slow platforms. This library contains functionality
to submit GPU workloads that should consume exactly a specific
amount of time.

Since v14: Since we are using multiple signals, walk list of batches
to terminate a batch to avoid using a single global batch. Cycle signals
between SIGRTMIN and SIGRTMAX properly.

Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: tomeu@tomeuvizoso.net
Reviewed-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
---
 .../intel-gpu-tools/intel-gpu-tools-docs.xml       |   1 +
 lib/Makefile.sources                               |   2 +
 lib/drmtest.c                                      |   3 +
 lib/igt.h                                          |   1 +
 lib/igt_dummyload.c                                | 302 +++++++++++++++++++++
 lib/igt_dummyload.h                                |  50 ++++
 6 files changed, 359 insertions(+)
 create mode 100644 lib/igt_dummyload.c
 create mode 100644 lib/igt_dummyload.h

diff --git a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
index c862f2a..55902ab 100644
--- a/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
+++ b/docs/reference/intel-gpu-tools/intel-gpu-tools-docs.xml
@@ -32,6 +32,7 @@
     <xi:include href="xml/intel_io.xml"/>
     <xi:include href="xml/igt_vc4.xml"/>
     <xi:include href="xml/igt_vgem.xml"/>
+    <xi:include href="xml/igt_dummyload.xml"/>
   </chapter>
   <xi:include href="xml/igt_test_programs.xml"/>
 
diff --git a/lib/Makefile.sources b/lib/Makefile.sources
index e8e277b..7fc5ec2 100644
--- a/lib/Makefile.sources
+++ b/lib/Makefile.sources
@@ -75,6 +75,8 @@ lib_source_list =	 	\
 	igt_draw.h		\
 	igt_pm.c		\
 	igt_pm.h		\
+	igt_dummyload.c		\
+	igt_dummyload.h		\
 	uwildmat/uwildmat.h	\
 	uwildmat/uwildmat.c	\
 	$(NULL)
diff --git a/lib/drmtest.c b/lib/drmtest.c
index 44abc7e..be1dc93 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -57,6 +57,7 @@
 #include "config.h"
 #include "intel_reg.h"
 #include "ioctl_wrappers.h"
+#include "igt_dummyload.h"
 
 /**
  * SECTION:drmtest
@@ -159,6 +160,8 @@ void gem_quiescent_gpu(int fd)
 	struct drm_i915_gem_exec_object2 obj;
 	unsigned ring;
 
+	igt_terminate_spin_batches();
+
 	memset(&obj, 0, sizeof(obj));
 	obj.handle = gem_create(fd, 4096);
 	gem_write(fd, obj.handle, 0, &bbe, sizeof(&bbe));
diff --git a/lib/igt.h b/lib/igt.h
index d751f24..a0028d5 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -32,6 +32,7 @@
 #include "igt_core.h"
 #include "igt_debugfs.h"
 #include "igt_draw.h"
+#include "igt_dummyload.h"
 #include "igt_fb.h"
 #include "igt_gt.h"
 #include "igt_kms.h"
diff --git a/lib/igt_dummyload.c b/lib/igt_dummyload.c
new file mode 100644
index 0000000..8a63311
--- /dev/null
+++ b/lib/igt_dummyload.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#include "igt.h"
+#include "igt_dummyload.h"
+#include <time.h>
+#include <signal.h>
+#include <sys/syscall.h>
+
+/**
+ * SECTION:igt_dummyload
+ * @short_description: Library for submitting GPU workloads
+ * @title: Dummyload
+ * @include: igt.h
+ *
+ * A lot of igt testcases need some GPU workload to make sure a race window is
+ * big enough. Unfortunately having a fixed amount of workload leads to
+ * spurious test failures or overly long runtimes on some fast/slow platforms.
+ * This library contains functionality to submit GPU workloads that should
+ * consume exactly a specific amount of time.
+ */
+
+#define LOCAL_I915_EXEC_BSD_SHIFT      (13)
+#define LOCAL_I915_EXEC_BSD_MASK       (3 << LOCAL_I915_EXEC_BSD_SHIFT)
+
+#define ENGINE_MASK  (I915_EXEC_RING_MASK | LOCAL_I915_EXEC_BSD_MASK)
+
+static const int bo_size = 4096;
+static struct igt_list spin_list = { &(spin_list), &(spin_list) };
+
+static void
+fill_object(struct drm_i915_gem_exec_object2 *obj, uint32_t gem_handle,
+	    struct drm_i915_gem_relocation_entry *relocs, uint32_t count)
+{
+	memset(obj, 0, sizeof(*obj));
+	obj->handle = gem_handle;
+	obj->relocation_count = count;
+	obj->relocs_ptr = (uintptr_t)relocs;
+}
+
+static void
+fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+	   uint32_t gem_handle, uint32_t offset,
+	   uint32_t read_domains, uint32_t write_domains)
+{
+	reloc->target_handle = gem_handle;
+	reloc->delta = 0;
+	reloc->offset = offset * sizeof(uint32_t);
+	reloc->presumed_offset = 0;
+	reloc->read_domains = read_domains;
+	reloc->write_domain = write_domains;
+}
+
+static uint32_t emit_recursive_batch(uint32_t **batch_, int fd, int engine,
+				     unsigned int dep_handle)
+{
+	const int gen = intel_gen(intel_get_drm_devid(fd));
+	struct drm_i915_gem_exec_object2 obj[2];
+	struct drm_i915_gem_relocation_entry relocs[2];
+	struct drm_i915_gem_execbuffer2 execbuf;
+	unsigned int engines[16];
+	unsigned int nengine, handle;
+	int i = 0, reloc_count = 0, buf_count = 0;
+	uint32_t *batch;
+
+	buf_count = 0;
+	nengine = 0;
+	if (engine < 0) {
+		for_each_engine(fd, engine)
+			if (engine)
+				engines[nengine++] = engine;
+	} else {
+		gem_require_ring(fd, engine);
+		engines[nengine++] = engine;
+	}
+	igt_require(nengine);
+
+	memset(&execbuf, 0, sizeof(execbuf));
+	memset(obj, 0, sizeof(obj));
+	memset(relocs, 0, sizeof(relocs));
+
+	execbuf.buffers_ptr = (uintptr_t) obj;
+	handle = gem_create(fd, bo_size);
+	batch = gem_mmap__gtt(fd, handle, bo_size, PROT_WRITE);
+	igt_assert(batch);
+	gem_set_domain(fd, handle,
+			I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+
+	if (dep_handle > 0) {
+		/* dummy write to dependency */
+		fill_object(&obj[buf_count], dep_handle, NULL, 0);
+		buf_count++;
+
+		fill_reloc(&relocs[reloc_count], dep_handle, 256,
+			   I915_GEM_DOMAIN_RENDER,
+			   I915_GEM_DOMAIN_RENDER);
+		reloc_count++;
+	}
+
+	if (gen >= 8) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8 | 1;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		batch[i++] = 0;
+	} else if (gen >= 6) {
+		batch[i++] = MI_BATCH_BUFFER_START | 1 << 8;
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+	} else {
+		batch[i++] = MI_BATCH_BUFFER_START | 2 << 6 |
+			((gen < 4) ? 1 : 0);
+		/* recurse */
+		fill_reloc(&relocs[reloc_count], handle, i,
+			   I915_GEM_DOMAIN_COMMAND, 0);
+		batch[i++] = 0;
+		if (gen < 4)
+			relocs[reloc_count].delta = 1;
+	}
+	reloc_count++;
+
+	fill_object(&obj[buf_count], handle, relocs, reloc_count);
+	buf_count++;
+
+	for (i = 0; i < nengine; i++) {
+		execbuf.flags = engines[i];
+		execbuf.flags &= ~ENGINE_MASK;
+		execbuf.buffer_count = buf_count;
+		gem_execbuf(fd, &execbuf);
+	}
+	*batch_ = batch;
+
+	return handle;
+}
+
+static void exit_batch_handler(int sig, siginfo_t *info, void *arg)
+{
+	struct sigaction act;
+	struct igt_spin *iter, *tmp;
+
+	igt_list_for_each_safe(iter, tmp, &spin_list, link) {
+		if (iter->signo == info->si_signo) {
+			*iter->batch = MI_BATCH_BUFFER_END;
+			__sync_synchronize();
+			break;
+		}
+	}
+
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = SIG_DFL;
+	igt_assert(sigaction(info->si_signo, &act, NULL) == 0);
+}
+
+
+void igt_terminate_spin_batches(void)
+{
+	struct igt_spin *iter, *tmp;
+
+	igt_list_for_each_safe(iter, tmp, &spin_list, link)
+		igt_spin_batch_end(iter);
+}
+
+/**
+ * igt_spin_batch_new:
+ * @fd: open i915 drm file descriptor
+ * @engine: Ring to execute batch OR'd with execbuf flags. If value is less
+ *          than 0, execute on all available rings.
+ * @dep_handle: handle to a buffer object dependency. If greater than 0, add a
+ *              relocation entry to this buffer within the batch.
+ *
+ * Start a recursive batch on a ring. Immediately returns a #igt_spin_t that
+ * contains the batch's handle that can be waited upon. The returned structure
+ * must be passed to igt_spin_batch_free() for post-processing.
+ *
+ * Returns:
+ * Structure with helper internal state for igt_spin_batch_free().
+ */
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle)
+{
+	uint32_t *batch;
+	igt_spin_t *spin = calloc(1, sizeof(struct igt_spin));
+	uint32_t handle = emit_recursive_batch(&batch, fd, engine, dep_handle);
+
+	igt_assert(gem_bo_busy(fd, handle));
+	igt_list_init(&spin->link);
+	spin->handle = handle;
+	spin->batch = batch;
+	spin->timer = NULL;
+	igt_list_add(&spin_list, &spin->link);
+
+	return spin;
+}
+
+/**
+ * igt_spin_batch_set_timeout:
+ * @spin: spin batch state from igt_spin_batch_new()
+ * @ns: amount of time in nanoseconds the batch continues to execute
+ *      before finishing.
+ *
+ * Specify a timeout. This ends the recursive batch associated with @spin after
+ * the timeout has elapsed.
+ */
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns)
+{
+	timer_t timer;
+	struct sigevent sev;
+	struct sigaction act, oldact;
+	struct itimerspec its;
+	static int spin_signo = 0;
+
+	igt_assert(ns > 0);
+	if (!spin)
+		return;
+
+	if (!spin_signo || spin_signo == SIGRTMAX)
+		spin_signo = SIGRTMIN;
+	spin->signo = ++spin_signo;
+
+	memset(&sev, 0, sizeof(sev));
+	sev.sigev_notify = SIGEV_SIGNAL | SIGEV_THREAD_ID;
+	sev.sigev_notify_thread_id = gettid();
+	sev.sigev_signo = spin->signo;
+	igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
+	igt_assert(timer > 0);
+
+	memset(&oldact, 0, sizeof(oldact));
+	memset(&act, 0, sizeof(act));
+	act.sa_sigaction = exit_batch_handler;
+	act.sa_flags = SA_SIGINFO;
+	igt_assert(sigaction(spin->signo, &act, &oldact) == 0);
+	igt_assert(oldact.sa_sigaction == NULL);
+
+	memset(&its, 0, sizeof(its));
+	its.it_value.tv_sec = ns / NSEC_PER_SEC;
+	its.it_value.tv_nsec = ns % NSEC_PER_SEC;
+	igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
+
+	spin->timer = timer;
+}
+
+/**
+ * igt_spin_batch_end:
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * End the recursive batch associated with @spin manually.
+ */
+void igt_spin_batch_end(igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	*spin->batch = MI_BATCH_BUFFER_END;
+	__sync_synchronize();
+}
+
+/**
+ * igt_spin_batch_free:
+ * @fd: open i915 drm file descriptor
+ * @spin: spin batch state from igt_spin_batch_new()
+ *
+ * This function does the necessary post-processing after starting a recursive
+ * batch with igt_spin_batch_new().
+ */
+void igt_spin_batch_free(int fd, igt_spin_t *spin)
+{
+	if (!spin)
+		return;
+
+	if (spin->timer > 0)
+		timer_delete(spin->timer);
+
+	igt_spin_batch_end(spin);
+	munmap(spin->batch, bo_size);
+	gem_close(fd, spin->handle);
+	igt_list_del(&spin->link);
+	free(spin);
+}
diff --git a/lib/igt_dummyload.h b/lib/igt_dummyload.h
new file mode 100644
index 0000000..8a24965
--- /dev/null
+++ b/lib/igt_dummyload.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2016 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.
+ *
+ */
+
+#ifndef __IGT_DUMMYLOAD_H__
+#define __IGT_DUMMYLOAD_H__
+
+#include "igt_aux.h"
+
+typedef struct igt_spin {
+	unsigned int handle;
+	uint32_t *batch;
+	timer_t timer;
+	int signo;
+	struct igt_list link;
+} igt_spin_t;
+
+
+igt_spin_t *
+igt_spin_batch_new(int fd, int engine, unsigned int dep_handle);
+
+void igt_spin_batch_set_timeout(igt_spin_t *spin, int64_t ns);
+
+void igt_spin_batch_end(igt_spin_t *spin);
+
+void igt_spin_batch_free(int fd, igt_spin_t *spin);
+
+void igt_terminate_spin_batches(void);
+
+#endif /* __IGT_DUMMYLOAD_H__ */
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2016-11-28  7:37 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-23 10:59 i-g-t dummyload/spin batch v10 Abdiel Janulgue
2016-11-23 10:59 ` [i-g-t PATCH v10 1/5] lib: Make signal helper definitions reusable Abdiel Janulgue
2016-11-23 10:59 ` [i-g-t PATCH v10 2/5] lib: add igt_dummyload Abdiel Janulgue
2016-11-23 11:47   ` Chris Wilson
2016-11-23 15:53     ` [i-g-t PATCH v11 " Abdiel Janulgue
2016-11-23 16:17       ` Chris Wilson
2016-11-24 10:16         ` [i-g-t PATCH v12 " Abdiel Janulgue
2016-11-25  9:17           ` Chris Wilson
2016-11-25 11:40             ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Abdiel Janulgue
2016-11-25 11:40               ` [i-g-t PATCH v13 3/6] lib: add igt_dummyload Abdiel Janulgue
2016-11-25 11:52               ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from the kernel Chris Wilson
2016-11-25 11:54               ` Chris Wilson
2016-11-25 14:41                 ` [i-g-t PATCH 2/6] igt_aux: Add some list helpers from wayland Abdiel Janulgue
2016-11-25 14:41                   ` [i-g-t PATCH v14 3/6] lib: add igt_dummyload Abdiel Janulgue
2016-11-25 15:19                     ` Chris Wilson
2016-11-28  7:37                       ` [i-g-t PATCH v15 " Abdiel Janulgue
2016-11-23 10:59 ` [i-g-t PATCH v10 3/5] igt/gem_wait: Use new igt_spin_batch Abdiel Janulgue
2016-11-23 10:59 ` [i-g-t PATCH v10 4/5] igt/kms_flip: " Abdiel Janulgue
2016-11-23 11:35   ` Chris Wilson
2016-11-23 10:59 ` [i-g-t PATCH v10 5/5] igt/kms_busy.c: " Abdiel Janulgue

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.