[igt-dev] [PATCH i-g-t] tests/kms_chamelium: add a latency test

Ser, Simon simon.ser at intel.com
Fri Sep 6 11:56:39 UTC 2019


On Fri, 2019-09-06 at 14:46 +0300, Simon Ser wrote:
> This new test creates a red and a green framebuffer, then alternatively shows
> one and the other for a while. We check that we correctly capture the
> alternating pattern with Chamelium.
> 
> We do our best to capture the pattern, which is tricky because of
> synchronization issues. We first show the red FB, start the capture, then
> play the alternating pattern, and stop the capture. We capture more frames than
> there are in the pattern to make sure the delay after starting the capture
> doesn't make us completely miss the pattern.
> 
> Signed-off-by: Simon Ser <simon.ser at intel.com>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Martin Peres <martin.peres at linux.intel.com>

TBH this isn't really a latency test, there's no timing measurement. I
don't want to do that with the Chamelium, because the local network
could be crowded and introduce a lot of extra latency randomly.

Maybe this should be a non-Chamelium test, just with plain old CRCs
coming from the GPU directly.

> ---
>  tests/kms_chamelium.c | 163 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 163 insertions(+)
> 
> diff --git a/tests/kms_chamelium.c b/tests/kms_chamelium.c
> index 6b6292497cd7..ba9f8acb600c 100644
> --- a/tests/kms_chamelium.c
> +++ b/tests/kms_chamelium.c
> @@ -2522,6 +2522,161 @@ test_hpd_storm_disable(data_t *data, struct chamelium_port *port, int width)
>  	igt_hpd_storm_reset(data->drm_fd);
>  }
>  
> +static void latency_page_flip_handler(int fd, unsigned seq, unsigned tv_sec,
> +				      unsigned tv_usec, void *data)
> +{
> +	int64_t *seq_ptr = data;
> +
> +	igt_debug("Got page-flip event (seq=%u)\n", seq);
> +	*seq_ptr = seq;
> +}
> +
> +#define TEST_LATENCY_PLAYBACK_FRAMES 20
> +#define TEST_LATENCY_CAPTURE_FRAMES (TEST_LATENCY_PLAYBACK_FRAMES + 10)
> +
> +static const char test_display_latency_desc[] =
> +	"Alternate between two different buffers at each page-flip, "
> +	"check there is no latency or tearing";
> +static void
> +test_display_latency(data_t *data, struct chamelium_port *port)
> +{
> +	igt_output_t *output;
> +	igt_plane_t *primary;
> +	struct igt_fb fbs[2];
> +	unsigned int fb_ids[2];
> +	struct chamelium_fb_crc_async_data *fb_crcs[2];
> +	drmModeModeInfo mode;
> +	drmModeConnector *connector;
> +	struct pollfd pfd = {0};
> +	drmEventContext drm_event = {0};
> +	int i, j, ret, captured_frames_count, start, end;
> +	int64_t prev_seq, seq;
> +	igt_crc_t *crcs, *expected_crcs[2];
> +
> +	reset_state(data, port);
> +
> +	output = prepare_output(data, port, TEST_EDID_BASE);
> +	connector = chamelium_port_get_connector(data->chamelium, port, false);
> +	primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
> +	igt_assert(primary);
> +
> +	igt_assert(connector->count_modes > 0);
> +	mode = connector->modes[0];
> +
> +	drmModeFreeConnector(connector);
> +
> +	fb_ids[0] = igt_create_color_pattern_fb(data->drm_fd,
> +						mode.hdisplay, mode.vdisplay,
> +						DRM_FORMAT_XRGB8888,
> +						LOCAL_DRM_FORMAT_MOD_NONE,
> +						1, 0, 0, &fbs[0]);
> +	igt_assert(fb_ids[0] > 0);
> +	fb_ids[1] = igt_create_color_pattern_fb(data->drm_fd,
> +						mode.hdisplay, mode.vdisplay,
> +						DRM_FORMAT_XRGB8888,
> +						LOCAL_DRM_FORMAT_MOD_NONE,
> +						0, 1, 0, &fbs[1]);
> +	igt_assert(fb_ids[1] > 0);
> +
> +	fb_crcs[0] = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +							    &fbs[0]);
> +	fb_crcs[1] = chamelium_calculate_fb_crc_async_start(data->drm_fd,
> +							    &fbs[1]);
> +
> +	igt_plane_set_fb(primary, &fbs[0]);
> +	igt_plane_set_size(primary, mode.hdisplay, mode.vdisplay);
> +	igt_output_override_mode(output, &mode);
> +	igt_display_commit2(&data->display, COMMIT_ATOMIC);
> +
> +	chamelium_start_capture(data->chamelium, port, 0, 0, 0, 0);
> +
> +	pfd.fd = data->drm_fd;
> +	pfd.events = POLLIN;
> +
> +	drm_event.version = 2;
> +	drm_event.page_flip_handler = latency_page_flip_handler;
> +
> +	/* Make sure we stop the alternating pattern with fb[1] */
> +	assert(TEST_LATENCY_PLAYBACK_FRAMES % 2 == 0);
> +
> +	prev_seq = -1;
> +	for (i = 0; i < TEST_LATENCY_PLAYBACK_FRAMES; i++) {
> +		igt_plane_set_fb(primary, &fbs[i % 2]);
> +
> +		igt_display_commit_atomic(&data->display,
> +					  DRM_MODE_ATOMIC_NONBLOCK |
> +					  DRM_MODE_PAGE_FLIP_EVENT,
> +					  &seq);
> +
> +		ret = poll(&pfd, 1, 1000);
> +		igt_assert_f(ret == 1, "poll returned %d, expected 1\n", ret);
> +		seq = -1;
> +		drmHandleEvent(data->drm_fd, &drm_event);
> +		igt_assert(seq >= 0);
> +
> +		if (prev_seq >= 0) {
> +			igt_assert((unsigned) (prev_seq + 1) == (unsigned) seq);
> +		}
> +		prev_seq = seq;
> +	}
> +
> +	/* Capture more frames than necessary, because we don't want to miss
> +	 * our alternating pattern. */
> +	chamelium_stop_capture(data->chamelium, TEST_LATENCY_CAPTURE_FRAMES);
> +	crcs = chamelium_read_captured_crcs(data->chamelium,
> +					    &captured_frames_count);
> +	igt_assert(captured_frames_count == TEST_LATENCY_CAPTURE_FRAMES);
> +
> +	igt_debug("Captured %d frames\n", captured_frames_count);
> +
> +	expected_crcs[0] = chamelium_calculate_fb_crc_async_finish(fb_crcs[0]);
> +	expected_crcs[1] = chamelium_calculate_fb_crc_async_finish(fb_crcs[1]);
> +
> +	/* Assuming reference CRCs A and B, the captured CRCs should look like:
> +	 * A A A A A B A B A B A B A B A B A B … A B A B B B B B B B
> +	 *           ^                                 ^
> +	 *           playback starts                   playback ends
> +	 */
> +	igt_debug("Reference CRC #0: %s\n", igt_crc_to_string(expected_crcs[0]));
> +	igt_debug("Reference CRC #1: %s\n", igt_crc_to_string(expected_crcs[1]));
> +	for (i = 0; i < captured_frames_count; i++) {
> +		igt_debug("Captured CRC #%d: %s\n", i,
> +			  igt_crc_to_string(&crcs[i]));
> +	}
> +
> +	igt_debug("Searching start and end of alternating pattern...\n");
> +	for (start = 0; start < captured_frames_count; start++) {
> +		if (!igt_check_crc_equal(expected_crcs[0], &crcs[start]))
> +			break;
> +	}
> +	for (end = captured_frames_count - 1; end >= 0; end--) {
> +		if (!igt_check_crc_equal(expected_crcs[1], &crcs[end]))
> +			break;
> +	}
> +	igt_debug("Alternating pattern starts at frame #%d and ends at "
> +		  "frame #%d\n", start, end);
> +	/* Make sure we captured a big enough chunk of the pattern */
> +	igt_assert_f(end - start > TEST_LATENCY_PLAYBACK_FRAMES / 2,
> +		     "Captured only %d frames of the alternating pattern, "
> +		     "that's not enough (expected more than %d)\n",
> +		     end - start, TEST_LATENCY_PLAYBACK_FRAMES / 2);
> +
> +	j = 1; /* crcs[start] should match expected_crcs[1] */
> +	for (i = start; i <= end; i++) {
> +		igt_assert_f(igt_check_crc_equal(expected_crcs[j % 2], &crcs[i]),
> +			     "Captured CRC #%d mismatches reference CRC #%d\n",
> +			     i, j % 2);
> +		j++;
> +	}
> +
> +	free(expected_crcs[0]);
> +	free(expected_crcs[1]);
> +	free(crcs);
> +
> +	igt_remove_fb(data->drm_fd, &fbs[0]);
> +	igt_remove_fb(data->drm_fd, &fbs[1]);
> +}
> +
>  static const struct edid *get_edid(enum test_edid edid)
>  {
>  	switch (edid) {
> @@ -2659,6 +2814,10 @@ igt_main
>  		connector_subtest("dp-audio-edid", DisplayPort)
>  			test_display_audio_edid(&data, port,
>  						TEST_EDID_DP_AUDIO);
> +
> +		igt_describe(test_display_latency_desc);
> +		connector_subtest("dp-latency", DisplayPort)
> +			test_display_latency(&data, port);
>  	}
>  
>  	igt_subtest_group {
> @@ -2820,6 +2979,10 @@ igt_main
>  
>  		connector_subtest("hdmi-aspect-ratio", HDMIA)
>  			test_display_aspect_ratio(&data, port);
> +
> +		igt_describe(test_display_latency_desc);
> +		connector_subtest("hdmi-latency", HDMIA)
> +			test_display_latency(&data, port);
>  	}
>  
>  	igt_subtest_group {


More information about the igt-dev mailing list