summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2016-08-09 19:01:05 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2016-08-09 19:03:14 +0100
commit48df4f23b3066d546c271997490f6e3acea70c02 (patch)
tree6c0ccd469eda9b11cbd8b4286bf71fb9a5233f51 /tests
parent9afd5458a40427996067460dfcc605a9cf5086a3 (diff)
igt/gem_busy: Stress test gem_busy() vs gem_close()
When doing lockless lookups using gem_busy(), one of the largest complications is ensuring that the bo doesn't disappear as we read it. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'tests')
-rw-r--r--tests/gem_busy.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/tests/gem_busy.c b/tests/gem_busy.c
index 940f05e7..22d38793 100644
--- a/tests/gem_busy.c
+++ b/tests/gem_busy.c
@@ -22,6 +22,7 @@
*/
#include "igt.h"
+#include "igt_rand.h"
#define LOCAL_EXEC_NO_RELOC (1<<11)
@@ -359,6 +360,91 @@ static void one(int fd, unsigned ring, uint32_t flags, unsigned test_flags)
gem_close(fd, obj[SCRATCH].handle);
}
+static void xchg_u32(void *array, unsigned i, unsigned j)
+{
+ uint32_t *u32 = array;
+ uint32_t tmp = u32[i];
+ u32[i] = u32[j];
+ u32[j] = tmp;
+}
+
+static void close_race(int fd)
+{
+#define N_HANDLES 4096
+ const int ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+ uint32_t *handles;
+ unsigned long *control;
+ unsigned long count = 0;
+ int i;
+
+ intel_require_memory(N_HANDLES, 4096, CHECK_RAM);
+
+ /* One thread spawning work and randomly closing fd.
+ * One background thread per cpu checking busyness.
+ */
+
+ control = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ igt_assert(control != MAP_FAILED);
+
+ handles = mmap(NULL, N_HANDLES*sizeof(*handles),
+ PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+ igt_assert(handles != MAP_FAILED);
+
+ for (i = 0; i < N_HANDLES; i++) {
+ handles[i] = gem_create(fd, 4096);
+ }
+
+ igt_fork(child, ncpus) {
+ struct drm_i915_gem_busy busy;
+ uint32_t indirection[N_HANDLES];
+
+ for (i = 0; i < N_HANDLES; i++)
+ indirection[i] = i;
+
+ hars_petruska_f54_1_random_perturb(child);
+
+ memset(&busy, 0, sizeof(busy));
+ do {
+ igt_permute_array(indirection, N_HANDLES, xchg_u32);
+ __sync_synchronize();
+ for (i = 0; i < N_HANDLES; i++) {
+ busy.handle = indirection[handles[i]];
+ /* Check that the busy computation doesn't
+ * explode in the face of random gem_close().
+ */
+ drmIoctl(fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
+ }
+ count++;
+ } while(*(volatile long *)control == 0);
+
+ igt_debug("child[%d]: count = %lu\n", child, count);
+ control[child] = count;
+ }
+
+ igt_until_timeout(20) {
+ int j = rand() % N_HANDLES;
+
+ gem_close(fd, handles[j]);
+ __sync_synchronize();
+ handles[j] = busy_blt(fd);
+
+ count++;
+ }
+ control[0] = 1;
+ igt_waitchildren();
+
+ for (i = 0; i < ncpus; i++)
+ control[ncpus + 1] += control[i + 1];
+ igt_info("Total execs %lu, busy-ioctls %lu\n",
+ count, control[ncpus + 1] * N_HANDLES);
+
+ for (i = 0; i < N_HANDLES; i++)
+ gem_close(fd, handles[i]);
+
+ munmap(handles, N_HANDLES * sizeof(*handles));
+ munmap(control, 4096);
+}
+
static bool has_semaphores(int fd)
{
struct drm_i915_getparam gp;
@@ -473,6 +559,12 @@ igt_main
}
}
+ igt_subtest_group {
+ igt_subtest("close-race") {
+ close_race(fd);
+ }
+ }
+
igt_fixture {
close(fd);
}