summaryrefslogtreecommitdiff
path: root/tests/perf_pmu.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2017-11-23 13:51:48 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2017-11-24 10:13:29 +0000
commit2a1c1c099113022f091f9e9585be88c6c9cefec5 (patch)
tree987bfb1806a94459aa989fb869b15ebd2ab3c91f /tests/perf_pmu.c
parent08a77fb147d7c831dfaf2a296d1c0b243ed46d0f (diff)
igt/perf_pmu: Recalibrate interrupt loop.
We have to be careful in our calibration loop, too slow and we timeout, too fast and we don't emit an interrupt! On fast legacy devices, we would overflow the calibration calcuation... v2: Give the time constants a name. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Diffstat (limited to 'tests/perf_pmu.c')
-rw-r--r--tests/perf_pmu.c115
1 files changed, 55 insertions, 60 deletions
diff --git a/tests/perf_pmu.c b/tests/perf_pmu.c
index 9cb679b2..a19fd2ac 100644
--- a/tests/perf_pmu.c
+++ b/tests/perf_pmu.c
@@ -40,6 +40,7 @@
#include "igt_core.h"
#include "igt_perf.h"
#include "igt_sysfs.h"
+#include "sw_sync.h"
IGT_TEST_DESCRIPTION("Test the i915 pmu perf interface");
@@ -787,18 +788,18 @@ static void cpu_hotplug(int gem_fd)
assert_within_epsilon(val, ref, tolerance);
}
-static unsigned long calibrate_nop(int fd, const unsigned int calibration_us)
+static unsigned long calibrate_nop(int fd, const uint64_t calibration_us)
{
- const unsigned int cal_min_us = calibration_us * 3;
+ const uint64_t cal_min_us = calibration_us * 3;
const unsigned int tolerance_pct = 10;
const uint32_t bbe = MI_BATCH_BUFFER_END;
const unsigned int loops = 17;
struct drm_i915_gem_exec_object2 obj = {};
- struct drm_i915_gem_execbuffer2 eb =
- { .buffer_count = 1, .buffers_ptr = (uintptr_t)&obj};
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffer_count = 1, .buffers_ptr = to_user_pointer(&obj),
+ };
struct timespec t_begin = { };
- long size, last_size;
- unsigned long ns;
+ uint64_t size, last_size, ns;
igt_nsec_elapsed(&t_begin);
@@ -828,81 +829,75 @@ static unsigned long calibrate_nop(int fd, const unsigned int calibration_us)
} while (igt_nsec_elapsed(&t_begin) / 1000 < cal_min_us ||
abs(size - last_size) > (size * tolerance_pct / 100));
- return size / sizeof(uint32_t);
+ return size;
}
-static void exec_nop(int gem_fd, unsigned long sz)
+static void
+test_interrupts(int gem_fd)
{
- struct drm_i915_gem_exec_object2 obj = {};
- struct drm_i915_gem_execbuffer2 eb =
- { .buffer_count = 1, .buffers_ptr = (uintptr_t)&obj};
const uint32_t bbe = MI_BATCH_BUFFER_END;
+ const unsigned int test_duration_ms = 1000;
+ struct drm_i915_gem_exec_object2 obj = { };
+ struct drm_i915_gem_execbuffer2 eb = {
+ .buffers_ptr = to_user_pointer(&obj),
+ .buffer_count = 1,
+ .flags = I915_EXEC_FENCE_OUT,
+ };
+ unsigned long sz;
+ igt_spin_t *spin;
+ const int target = 30;
struct pollfd pfd;
- int fence;
+ uint64_t idle, busy;
+ int fd;
- sz = ALIGN(sz, sizeof(uint32_t));
+ sz = calibrate_nop(gem_fd, test_duration_ms * 1000 / target);
+ gem_quiescent_gpu(gem_fd);
+
+ fd = open_pmu(I915_PMU_INTERRUPTS);
+ spin = igt_spin_batch_new(gem_fd, 0, 0, 0);
obj.handle = gem_create(gem_fd, sz);
gem_write(gem_fd, obj.handle, sz - sizeof(bbe), &bbe, sizeof(bbe));
- eb.flags = I915_EXEC_RENDER | I915_EXEC_FENCE_OUT;
-
- gem_execbuf_wr(gem_fd, &eb);
- fence = eb.rsvd2 >> 32;
-
- /*
- * Poll on the output fence to ensure user interrupts will be
- * generated and listened to.
- */
- pfd.fd = fence;
pfd.events = POLLIN;
- igt_assert_eq(poll(&pfd, 1, -1), 1);
-
- close(fence);
- gem_close(gem_fd, obj.handle);
-}
-
-static void
-test_interrupts(int gem_fd)
-{
- const unsigned int calibration_us = 250000;
- const unsigned int batch_len_us = 100000;
- const unsigned int batch_count = 3e6 / batch_len_us;
- uint64_t idle, busy, prev;
- unsigned long cal, sz;
- unsigned int i;
- int fd;
-
- fd = open_pmu(I915_PMU_INTERRUPTS);
-
- cal = calibrate_nop(gem_fd, calibration_us);
- sz = batch_len_us * cal / calibration_us;
-
- gem_quiescent_gpu(gem_fd);
+ pfd.fd = -1;
+ for (int i = 0; i < target; i++) {
+ int new;
+
+ /* Merge all the fences together so we can wait on them all */
+ gem_execbuf_wr(gem_fd, &eb);
+ new = eb.rsvd2 >> 32;
+ if (pfd.fd == -1) {
+ pfd.fd = new;
+ } else {
+ int old = pfd.fd;
+ pfd.fd = sync_fence_merge(old, new);
+ close(old);
+ close(new);
+ }
+ }
/* Wait for idle state. */
- prev = pmu_read_single(fd);
- idle = prev + 1;
- while (idle != prev) {
- usleep(1e6);
- prev = idle;
+ idle = pmu_read_single(fd);
+ do {
+ busy = idle;
+ usleep(1e3);
idle = pmu_read_single(fd);
- }
+ } while (idle != busy);
- igt_assert_eq(idle - prev, 0);
+ /* Install the fences and enable signaling */
+ igt_assert_eq(poll(&pfd, 1, 10), 0);
- /*
- * Send some no-op batches waiting on output fences to
- * ensure interrupts.
- */
- for (i = 0; i < batch_count; i++)
- exec_nop(gem_fd, sz);
+ /* Unplug the calibrated queue and wait for all the fences */
+ igt_spin_batch_free(gem_fd, spin);
+ igt_assert_eq(poll(&pfd, 1, 2 * test_duration_ms), 1);
+ close(pfd.fd);
/* Check at least as many interrupts has been generated. */
busy = pmu_read_single(fd) - idle;
close(fd);
- igt_assert(busy >= batch_count);
+ igt_assert_lte(target, busy);
}
static void