[Intel-gfx] [PATCH igt] igt/kms_flip: Calibrate timestamp errors

Chris Wilson chris at chris-wilson.co.uk
Mon Oct 24 08:54:52 UTC 2016


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.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 tests/kms_flip.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 71 insertions(+), 2 deletions(-)

diff --git a/tests/kms_flip.c b/tests/kms_flip.c
index b30e07c..44aec75 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)
@@ -175,6 +177,8 @@ struct test_output {
 	int seq_step;
 	unsigned int pending_events;
 	int flip_count;
+
+	double ts_error;
 };
 
 
@@ -698,7 +702,7 @@ static void check_state(const struct test_output *o, const struct event_state *e
 			  elapsed, expected, expected * 0.005,
 			  fabs((elapsed - expected) / expected) * 100);
 
-		igt_assert_f(fabs((elapsed - expected) / expected) <= 0.005,
+		igt_assert_f(fabs(elapsed - expected) / expected <= o->ts_error,
 			     "inconsistent %s ts/seq: last %ld.%06ld/%u, current %ld.%06ld/%u: elapsed=%.1fus expected=%.1fus\n",
 			     es->name, es->last_ts.tv_sec, es->last_ts.tv_usec, es->last_seq,
 			     es->current_ts.tv_sec, es->current_ts.tv_usec, es->current_seq,
@@ -1301,6 +1305,71 @@ static void free_test_output(struct test_output *o)
 	}
 }
 
+static double 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;
+	double median;
+	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);
+	median = igt_stats_get_median(&stats);
+
+	igt_info("Expected frametime: %.0fus; measured %.1fus +- %.3fus accuracy %.2f%%; median %.1fus error=%.1f%%\n",
+		 expected, mean, stddev, 100 * 6 * stddev / mean,
+		 median, 100* fabs(median - expected) / expected);
+	igt_assert(6 * stddev / mean < 0.005); /* 99% accuracy within 0.5% */
+	igt_require(fabs(mean - expected) < 2*stddev);
+
+	return 2*fabs(median - expected) / expected;
+}
+
 static void run_test_on_crtc_set(struct test_output *o, int *crtc_idxs,
 				 int crtc_count, int duration_ms)
 {
@@ -1404,7 +1473,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);
+		o->ts_error = calibrate_ts(o, crtc_idxs[0]);
 
 	igt_assert_eq(do_page_flip(o, o->fb_ids[1], true), 0);
 	wait_for_events(o);
-- 
2.10.1



More information about the Intel-gfx mailing list