diff --git a/tests/gem_exec_latency.c b/tests/gem_exec_latency.c
index de16322a6..c2fdf7ee2 100644
--- a/tests/gem_exec_latency.c
+++ b/tests/gem_exec_latency.c
@@ -258,13 +258,12 @@ static void latency_from_ring(int fd,
 	const int gen = intel_gen(intel_get_drm_devid(fd));
 	const int has_64bit_reloc = gen >= 8;
 	struct drm_i915_gem_exec_object2 obj[3];
-	struct drm_i915_gem_relocation_entry reloc;
 	struct drm_i915_gem_execbuffer2 execbuf;
-	const unsigned int repeats = ring_size / 2;
+	uint64_t presumed_offset;
 	unsigned int other;
 	uint32_t *map, *results;
 	uint32_t ctx[2] = {};
-	int i, j;
+	int j;
 
 	if (flags & PREEMPT) {
 		ctx[0] = gem_context_create(fd);
@@ -294,102 +293,83 @@ static void latency_from_ring(int fd,
 	map[0] = MI_BATCH_BUFFER_END;
 	gem_execbuf(fd, &execbuf);
 
-	memset(&reloc,0, sizeof(reloc));
-	obj[2].relocation_count = 1;
-	obj[2].relocs_ptr = to_user_pointer(&reloc);
-
 	gem_set_domain(fd, obj[2].handle,
 		       I915_GEM_DOMAIN_GTT,
 		       I915_GEM_DOMAIN_GTT);
+	presumed_offset = obj[1].offset;
+	for (j = 0; j < 1024; j++) {
+		uint64_t offset = sizeof(uint32_t) * j + presumed_offset;
+		int i = 16 * j;
 
-	reloc.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
-	reloc.write_domain = I915_GEM_DOMAIN_INSTRUCTION;
-	reloc.presumed_offset = obj[1].offset;
-	reloc.target_handle = flags & CORK ? 1 : 0;
+		/* MI_STORE_REG_MEM */
+		map[i++] = 0x24 << 23 | 1;
+		if (has_64bit_reloc)
+			map[i-1]++;
+		map[i++] = RCS_TIMESTAMP; /* ring local! */
+		map[i++] = offset;
+		if (has_64bit_reloc)
+			map[i++] = offset >> 32;
+
+		map[i++] = MI_BATCH_BUFFER_END;
+	}
+	igt_assert(ring_size <= 1024);
 
 	for_each_physical_engine(fd, other) {
-		igt_spin_t *spin = NULL;
-		IGT_CORK_HANDLE(c);
-
-		gem_set_domain(fd, obj[2].handle,
-			       I915_GEM_DOMAIN_GTT,
-			       I915_GEM_DOMAIN_GTT);
-
-		if (flags & PREEMPT)
-			spin = __igt_spin_batch_new(fd,
-						    .ctx = ctx[0],
-						    .engine = ring);
-
-		if (flags & CORK) {
-			obj[0].handle = igt_cork_plug(&c, fd);
-			execbuf.buffers_ptr = to_user_pointer(&obj[0]);
-			execbuf.buffer_count = 3;
-		}
+		if (flags & PREEMPT && other == ring)
+			continue;
+
+		for (int qlen = 1; qlen < ring_size/2; qlen *= 2) {
+			unsigned int count = 32 * ring_size / qlen;
+			igt_stats_t stats;
+
+			igt_stats_init_with_size(&stats, count);
+			for (unsigned int rep = 0; rep < count; rep++) {
+				igt_spin_t *spin = NULL;
+				IGT_CORK_HANDLE(c);
+
+				if (flags & PREEMPT)
+					spin = __igt_spin_batch_new(fd,
+								    .ctx = ctx[0],
+								    .engine = ring);
+
+				if (flags & CORK) {
+					obj[0].handle = igt_cork_plug(&c, fd);
+					execbuf.buffers_ptr = to_user_pointer(&obj[0]);
+					execbuf.buffer_count = 3;
+				}
 
-		for (j = 0; j < repeats; j++) {
-			uint64_t offset;
-
-			execbuf.flags &= ~ENGINE_FLAGS;
-			execbuf.flags |= ring;
-
-			execbuf.batch_start_offset = 64 * j;
-			reloc.offset =
-				execbuf.batch_start_offset + sizeof(uint32_t);
-			reloc.delta = sizeof(uint32_t) * j;
-
-			reloc.presumed_offset = obj[1].offset;
-			offset = reloc.presumed_offset;
-			offset += reloc.delta;
-
-			i = 16 * j;
-			/* MI_STORE_REG_MEM */
-			map[i++] = 0x24 << 23 | 1;
-			if (has_64bit_reloc)
-				map[i-1]++;
-			map[i++] = RCS_TIMESTAMP; /* ring local! */
-			map[i++] = offset;
-			if (has_64bit_reloc)
-				map[i++] = offset >> 32;
-			map[i++] = MI_BATCH_BUFFER_END;
-
-			gem_execbuf(fd, &execbuf);
-
-			execbuf.flags &= ~ENGINE_FLAGS;
-			execbuf.flags |= other;
-
-			execbuf.batch_start_offset = 64 * (j + repeats);
-			reloc.offset =
-				execbuf.batch_start_offset + sizeof(uint32_t);
-			reloc.delta = sizeof(uint32_t) * (j + repeats);
-
-			reloc.presumed_offset = obj[1].offset;
-			offset = reloc.presumed_offset;
-			offset += reloc.delta;
-
-			i = 16 * (j + repeats);
-			/* MI_STORE_REG_MEM */
-			map[i++] = 0x24 << 23 | 1;
-			if (has_64bit_reloc)
-				map[i-1]++;
-			map[i++] = RCS_TIMESTAMP; /* ring local! */
-			map[i++] = offset;
-			if (has_64bit_reloc)
-				map[i++] = offset >> 32;
-			map[i++] = MI_BATCH_BUFFER_END;
-
-			gem_execbuf(fd, &execbuf);
-		}
+				for (j = 0; j < qlen; j++) {
+					execbuf.flags &= ~ENGINE_FLAGS;
+					execbuf.flags |= ring;
+					execbuf.batch_start_offset = 64 * j;
+
+					gem_execbuf(fd, &execbuf);
 
-		if (flags & CORK)
-			igt_cork_unplug(&c);
-		gem_set_domain(fd, obj[1].handle,
-			       I915_GEM_DOMAIN_GTT,
-			       I915_GEM_DOMAIN_GTT);
-		igt_spin_batch_free(fd, spin);
+					execbuf.flags &= ~ENGINE_FLAGS;
+					execbuf.flags |= other;
+					execbuf.batch_start_offset = 64 * (j + qlen);
 
-		igt_info("%s-%s delay: %.2f\n",
-			 name, e__->name,
-			 (results[2*repeats-1] - results[0]) / (double)repeats);
+					gem_execbuf(fd, &execbuf);
+				}
+
+				if (flags & CORK)
+					igt_cork_unplug(&c);
+				gem_set_domain(fd, obj[1].handle,
+					       I915_GEM_DOMAIN_GTT,
+					       I915_GEM_DOMAIN_GTT);
+				igt_spin_batch_free(fd, spin);
+
+				igt_assert_eq_u64(obj[1].offset,
+						  presumed_offset);
+				igt_stats_push(&stats,
+					       ((uint64_t)(results[2*qlen-1] - results[0]) << 32) / qlen);
+			}
+
+			igt_info("%s-%s-%d delay: %.2f\n",
+				 name, e__->name, qlen,
+				 igt_stats_get_median(&stats) / (1ull << 32));
+			igt_stats_fini(&stats);
+		}
 	}
 
 	munmap(map, 64*1024);
@@ -710,6 +690,11 @@ igt_main
 						latency_from_ring(device,
 								  e->exec_id | e->flags,
 								  e->name, PREEMPT);
+
+					igt_subtest_f("%s-preemption-queued", e->name)
+						latency_from_ring(device,
+								  e->exec_id | e->flags,
+								  e->name, PREEMPT | CORK);
 				}
 			}
 		}
