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

Daniel Vetter daniel at ffwll.ch
Mon Oct 24 09:14:31 UTC 2016


On Mon, Oct 24, 2016 at 09:54:52AM +0100, Chris Wilson wrote:
> 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>

Yeah, throwing some decent stats at this makes sense.

> ---
>  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);

I think an igt_require_f here with an explanation of what's going on would
be good here.

Also with this patch we should be able to throw out the hacks for tv-out.
I only added those because the reported mode-timings are massively off
(due to the magic tv scaler thing) from the real timestamps we receive.
Auto-detecting this is much better.

And another issue: Failing to match the reported mode timings is a driver
bug. I think a separate testcase which _only_ does the ts calibration (and
makes it a fail/pass instead of require/pass) would be great. I think
having an expectation that the timings userspace asks for is the timing it
gets would be great for kms ;-)

Ack on the patch.
-Daniel

> +
> +	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
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the Intel-gfx mailing list