summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2016-10-24 09:35:17 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2016-10-24 11:20:18 +0100
commit1df15aff40282afc5bdb111550beb218a53f615e (patch)
tree5ca5cd20d9da1d1ab7424406a3b8653d5c4ee85a
parent364f9eca192de94bd250ba63f0d418d993896ee7 (diff)
igt/kms_flip: Calibrate timestamp errors
We assert that the interval between a vblank and a flip corresponds with the computed frametime derived from the modeline. However, historically the dotclock is unreliable (in error of about 1%) for VBT supplied data about LVDS panels - the situation looks to be much improved with eDP at least. The simple fact that we cannot rely on the manufacturer's supplied modeline causes us to fail the test. So before we claim a driver failure, do a calibration pass and check for inconsistencies with the modeline. v2: Refine the failure message when skipping Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--tests/kms_flip.c68
1 files changed, 67 insertions, 1 deletions
diff --git a/tests/kms_flip.c b/tests/kms_flip.c
index b30e07c9..9829b355 100644
--- a/tests/kms_flip.c
+++ b/tests/kms_flip.c
@@ -26,6 +26,7 @@
#endif
#include "igt.h"
+
#include <cairo.h>
#include <errno.h>
#include <fcntl.h>
@@ -43,6 +44,7 @@
#include <time.h>
#include <pthread.h>
+#include "igt_stats.h"
#define TEST_DPMS (1 << 0)
#define TEST_WITH_DUMMY_BCS (1 << 1)
@@ -1301,6 +1303,70 @@ static void free_test_output(struct test_output *o)
}
}
+static void calibrate_ts(struct test_output *o, int crtc_idx)
+{
+#define CALIBRATE_TS_STEPS 16
+ drmVBlank wait;
+ igt_stats_t stats;
+ uint32_t last_seq;
+ uint64_t last_timestamp;
+ double expected;
+ double mean;
+ double stddev;
+ int n;
+
+ memset(&wait, 0, sizeof(wait));
+ wait.request.type = kmstest_get_vbl_flag(crtc_idx);
+ wait.request.type |= DRM_VBLANK_ABSOLUTE | DRM_VBLANK_NEXTONMISS;
+ do_or_die(drmWaitVBlank(drm_fd, &wait));
+
+ last_seq = wait.reply.sequence;
+ last_timestamp = wait.reply.tval_sec;
+ last_timestamp *= 1000000;
+ last_timestamp += wait.reply.tval_usec;
+
+ memset(&wait, 0, sizeof(wait));
+ wait.request.type = kmstest_get_vbl_flag(crtc_idx);
+ wait.request.type |= DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
+ wait.request.sequence = last_seq;
+ for (n = 0; n < CALIBRATE_TS_STEPS; n++) {
+ ++wait.request.sequence;
+ do_or_die(drmWaitVBlank(drm_fd, &wait));
+ }
+
+ igt_stats_init_with_size(&stats, CALIBRATE_TS_STEPS);
+ for (n = 0; n < CALIBRATE_TS_STEPS; n++) {
+ struct drm_event_vblank ev;
+ uint64_t now;
+
+ igt_assert(read(drm_fd, &ev, sizeof(ev)) == sizeof(ev));
+ igt_assert_eq(ev.sequence, last_seq + 1);
+
+ now = ev.tv_sec;
+ now *= 1000000;
+ now += ev.tv_usec;
+
+ igt_stats_push(&stats, now - last_timestamp);
+
+ last_timestamp = now;
+ last_seq = ev.sequence;
+ }
+
+ expected = frame_time(o);
+
+ mean = igt_stats_get_mean(&stats);
+ stddev = igt_stats_get_std_deviation(&stats);
+
+ igt_info("Expected frametime: %.0fus; measured %.1fus +- %.3fus accuracy %.2f%%\n",
+ expected, mean, stddev, 100 * 6 * stddev / mean);
+ igt_assert(6 * stddev / mean < 0.005); /* 99% accuracy within 0.5% */
+
+ igt_require_f(fabs(mean - expected) < 2*stddev,
+ "vblank interval differs from modeline! expected %.1fus, measured %1.fus +- %.3fus, difference %.1fus (%.1f sigma)\n",
+ expected, mean, stddev,
+ fabs(mean - expected), fabs(mean - expected) / stddev);
+}
+
static void run_test_on_crtc_set(struct test_output *o, int *crtc_idxs,
int crtc_count, int duration_ms)
{
@@ -1404,7 +1470,7 @@ static void run_test_on_crtc_set(struct test_output *o, int *crtc_idxs,
/* quiescent the hw a bit so ensure we don't miss a single frame */
if (o->flags & TEST_CHECK_TS)
- sleep(1);
+ calibrate_ts(o, crtc_idxs[0]);
igt_assert_eq(do_page_flip(o, o->fb_ids[1], true), 0);
wait_for_events(o);