[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