Doing modeset on internal panels may have a considerable overhead due to
the panel specific power sequencing delays. To avoid long test runtimes
limit the runtime of each subtest. Randomize the plane/pipe combinations
to preserve the test coverage on such panels at least over multiple test
runs.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103334
Cc: Maarten Lankhorst <maarten.lankho...@linux.intel.com>
Signed-off-by: Imre Deak <imre.d...@intel.com>
---
 tests/kms_atomic_transition.c | 175 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 150 insertions(+), 25 deletions(-)

diff --git a/tests/kms_atomic_transition.c b/tests/kms_atomic_transition.c
index 4c295125..ac67fc3a 100644
--- a/tests/kms_atomic_transition.c
+++ b/tests/kms_atomic_transition.c
@@ -39,6 +39,14 @@
 #define DRM_CAP_CURSOR_HEIGHT 0x9
 #endif
 
+#define MAX_SUBTEST_DURATION_NS (20ULL * NSEC_PER_SEC)
+
+struct test_config {
+       igt_display_t *display;
+       bool user_seed;
+       int seed;
+};
+
 struct plane_parms {
        struct igt_fb *fb;
        uint32_t width, height;
@@ -401,6 +409,28 @@ static void wait_for_transition(igt_display_t *display, 
enum pipe pipe, bool non
        }
 }
 
+/* Copied from https://benpfaff.org/writings/clc/shuffle.html */
+static void shuffle_array(uint32_t *array, int size, int seed)
+{
+       int i;
+
+       for (i = 0; i < size; i++) {
+               int j = i + rand() / (RAND_MAX / (size - i) + 1);
+
+               igt_swap(array[i], array[j]);
+       }
+}
+
+static void init_combination_array(uint32_t *array, int size, int seed)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               array[i] = i;
+
+       shuffle_array(array, size, seed);
+}
+
 /*
  * 1. Set primary plane to a known fb.
  * 2. Make sure getcrtc returns the correct fb id.
@@ -411,19 +441,27 @@ static void wait_for_transition(igt_display_t *display, 
enum pipe pipe, bool non
  * so test this and make sure it works.
  */
 static void
-run_transition_test(igt_display_t *display, enum pipe pipe, igt_output_t 
*output,
-               enum transition_type type, bool nonblocking, bool fencing)
+run_transition_test(struct test_config *test_config, enum pipe pipe,
+                   igt_output_t *output, enum transition_type type,
+                   bool nonblocking, bool fencing)
 {
        struct igt_fb fb, argb_fb, sprite_fb;
        drmModeModeInfo *mode, override_mode;
+       igt_display_t *display = test_config->display;
        igt_plane_t *plane;
        igt_pipe_t *pipe_obj = &display->pipes[pipe];
        uint32_t iter_max = 1 << pipe_obj->n_planes, i;
+       uint32_t *plane_combinations;
+       struct timespec start = { };
        struct plane_parms parms[pipe_obj->n_planes];
        bool skip_test = false;
        unsigned flags = 0;
        int ret;
 
+       plane_combinations = malloc(sizeof(*plane_combinations) * iter_max);
+       igt_assert(plane_combinations);
+       init_combination_array(plane_combinations, iter_max, test_config->seed);
+
        if (fencing)
                prepare_fencing(display, pipe);
        else
@@ -527,39 +565,59 @@ run_transition_test(igt_display_t *display, enum pipe 
pipe, igt_output_t *output
                goto cleanup;
        }
 
+       igt_nsec_elapsed(&start);
+
        for (i = 0; i < iter_max; i++) {
                igt_output_set_pipe(output, pipe);
 
-               wm_setup_plane(display, pipe, i, parms, fencing);
+               wm_setup_plane(display, pipe, plane_combinations[i], parms,
+                              fencing);
 
-               atomic_commit(display, pipe, flags, (void *)(unsigned long)i, 
fencing);
+               atomic_commit(display, pipe, flags,
+                             (void *)(unsigned long)plane_combinations[i],
+                             fencing);
                wait_for_transition(display, pipe, nonblocking, fencing);
 
                if (type == TRANSITION_MODESET_DISABLE) {
+                       if (igt_nsec_elapsed(&start) >= MAX_SUBTEST_DURATION_NS)
+                               goto cleanup;
+
                        igt_output_set_pipe(output, PIPE_NONE);
 
                        wm_setup_plane(display, pipe, 0, parms, fencing);
 
                        atomic_commit(display, pipe, flags, (void *) 0UL, 
fencing);
                        wait_for_transition(display, pipe, nonblocking, 
fencing);
+
                } else {
                        uint32_t j;
 
                        /* i -> i+1 will be done when i increases, can be 
skipped here */
                        for (j = iter_max - 1; j > i + 1; j--) {
-                               wm_setup_plane(display, pipe, j, parms, 
fencing);
+                               if (igt_nsec_elapsed(&start) >= 
MAX_SUBTEST_DURATION_NS)
+                                       goto cleanup;
+
+                               wm_setup_plane(display, pipe,
+                                              plane_combinations[j], parms,
+                                              fencing);
 
                                if (type == TRANSITION_MODESET)
                                        igt_output_override_mode(output, 
&override_mode);
 
-                               atomic_commit(display, pipe, flags, (void 
*)(unsigned long) j, fencing);
+                               atomic_commit(display, pipe, flags,
+                                             (void *)(unsigned 
long)plane_combinations[j],
+                                             fencing);
                                wait_for_transition(display, pipe, nonblocking, 
fencing);
 
-                               wm_setup_plane(display, pipe, i, parms, 
fencing);
+                               wm_setup_plane(display, pipe,
+                                              plane_combinations[i], parms,
+                                              fencing);
                                if (type == TRANSITION_MODESET)
                                        igt_output_override_mode(output, NULL);
 
-                               atomic_commit(display, pipe, flags, (void 
*)(unsigned long) i, fencing);
+                               atomic_commit(display, pipe, flags,
+                                             (void *)(unsigned 
long)plane_combinations[i],
+                                             fencing);
                                wait_for_transition(display, pipe, nonblocking, 
fencing);
                        }
                }
@@ -579,6 +637,9 @@ cleanup:
        igt_remove_fb(display->drm_fd, &fb);
        igt_remove_fb(display->drm_fd, &argb_fb);
        igt_remove_fb(display->drm_fd, &sprite_fb);
+
+       free(plane_combinations);
+
        if (skip_test)
                igt_skip("Atomic nonblocking modesets are not supported.\n");
 }
@@ -696,16 +757,24 @@ static void collect_crcs_mask(igt_pipe_crc_t **pipe_crcs, 
unsigned mask, igt_crc
        }
 }
 
-static void run_modeset_tests(igt_display_t *display, int howmany, bool 
nonblocking, bool fencing)
+static void run_modeset_tests(struct test_config *test_config, int howmany,
+                             bool nonblocking, bool fencing)
 {
+       igt_display_t *display = test_config->display;
        struct igt_fb fbs[2];
        int i, j;
        unsigned iter_max = 1 << display->n_pipes;
+       uint32_t *pipe_combinations;
+       struct timespec start = { };
        igt_pipe_crc_t *pipe_crcs[IGT_MAX_PIPES] = { 0 };
        igt_output_t *output;
        unsigned width = 0, height = 0;
        bool skip_test = false;
 
+       pipe_combinations = malloc(sizeof(*pipe_combinations) * iter_max);
+       igt_assert(pipe_combinations);
+       init_combination_array(pipe_combinations, iter_max, test_config->seed);
+
        for_each_connected_output(display, output) {
                drmModeModeInfo *mode = igt_output_get_mode(output);
 
@@ -757,6 +826,8 @@ static void run_modeset_tests(igt_display_t *display, int 
howmany, bool nonblock
 
        igt_display_commit2(display, COMMIT_ATOMIC);
 
+       igt_nsec_elapsed(&start);
+
        for (i = 0; i < iter_max; i++) {
                igt_crc_t crcs[5][IGT_MAX_PIPES];
                unsigned event_mask;
@@ -773,6 +844,9 @@ static void run_modeset_tests(igt_display_t *display, int 
howmany, bool nonblock
                collect_crcs_mask(pipe_crcs, i, crcs[0]);
 
                for (j = iter_max - 1; j > i + 1; j--) {
+                       if (igt_nsec_elapsed(&start) >= MAX_SUBTEST_DURATION_NS)
+                               goto cleanup;
+
                        if (hweight32(j) > howmany)
                                continue;
 
@@ -828,13 +902,18 @@ cleanup:
        igt_remove_fb(display->drm_fd, &fbs[1]);
        igt_remove_fb(display->drm_fd, &fbs[0]);
 
+       free(pipe_combinations);
+
        if (skip_test)
                igt_skip("Atomic nonblocking modesets are not supported.\n");
 
 }
 
-static void run_modeset_transition(igt_display_t *display, int 
requested_outputs, bool nonblocking, bool fencing)
+static void run_modeset_transition(struct test_config *test_config,
+                                  int requested_outputs, bool nonblocking,
+                                  bool fencing)
 {
+       igt_display_t *display = test_config->display;
        igt_output_t *outputs[IGT_MAX_PIPES] = {};
        int num_outputs = 0;
        enum pipe pipe;
@@ -861,16 +940,41 @@ static void run_modeset_transition(igt_display_t 
*display, int requested_outputs
                      "Should have at least %i outputs, found %i\n",
                      requested_outputs, num_outputs);
 
-       run_modeset_tests(display, requested_outputs, nonblocking, fencing);
+       run_modeset_tests(test_config, requested_outputs, nonblocking, fencing);
 }
 
-igt_main
+static int opt_handler(int option, int option_index, void *handler_data)
 {
+       struct test_config *test_config = handler_data;
+
+       switch (option) {
+       case 's':
+               test_config->user_seed = true;
+               test_config->seed = strtol(optarg, NULL, 0);
+               break;
+       default:
+               igt_assert(false);
+       }
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       const char *help_str =
+               "  --seed       Seed for random number generator\n";
+       struct option long_options[] = {
+               { "seed",    required_argument, NULL, 's' },
+               { },
+       };
+       struct test_config test_config = { };
        igt_display_t display;
        igt_output_t *output;
        enum pipe pipe;
        int i;
 
+       igt_subtest_init_parse_opts(&argc, argv, "", long_options, help_str,
+                                   opt_handler, &test_config);
        igt_skip_on_simulation();
 
        igt_fixture {
@@ -883,6 +987,15 @@ igt_main
                igt_require(display.is_atomic);
 
                igt_display_require_output(&display);
+
+               test_config.display = &display;
+               if (!test_config.user_seed)
+                       test_config.seed = time(NULL);
+
+               srand(test_config.seed);
+
+               igt_info("Running tests randomized with seed %d\n",
+                        test_config.seed);
        }
 
        igt_subtest("plane-primary-toggle-with-vblank-wait")
@@ -891,55 +1004,67 @@ igt_main
 
        igt_subtest("plane-all-transition")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_PLANES, false, false);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_PLANES, false, false);
 
        igt_subtest("plane-all-transition-fencing")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_PLANES, false, true);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_PLANES, false, true);
 
        igt_subtest("plane-all-transition-nonblocking")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_PLANES, true, false);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_PLANES, true, false);
 
        igt_subtest("plane-all-transition-nonblocking-fencing")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_PLANES, true, true);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_PLANES, true, true);
 
        igt_subtest("plane-use-after-nonblocking-unbind")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_AFTER_FREE, true, false);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_AFTER_FREE, true, false);
 
        igt_subtest("plane-use-after-nonblocking-unbind-fencing")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_AFTER_FREE, true, true);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_AFTER_FREE, true, true);
 
        igt_subtest("plane-all-modeset-transition")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_MODESET, false, false);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_MODESET, false, false);
 
        igt_subtest("plane-all-modeset-transition-fencing")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_MODESET, false, true);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_MODESET, false, true);
 
        igt_subtest("plane-toggle-modeset-transition")
                for_each_pipe_with_valid_output(&display, pipe, output)
-                       run_transition_test(&display, pipe, output, 
TRANSITION_MODESET_DISABLE, false, false);
+                       run_transition_test(&test_config, pipe, output,
+                                           TRANSITION_MODESET_DISABLE,
+                                           false, false);
 
        for (i = 1; i <= IGT_MAX_PIPES; i++) {
                igt_subtest_f("%ix-modeset-transitions", i)
-                       run_modeset_transition(&display, i, false, false);
+                       run_modeset_transition(&test_config, i, false, false);
 
                igt_subtest_f("%ix-modeset-transitions-nonblocking", i)
-                       run_modeset_transition(&display, i, true, false);
+                       run_modeset_transition(&test_config, i, true, false);
 
                igt_subtest_f("%ix-modeset-transitions-fencing", i)
-                       run_modeset_transition(&display, i, false, true);
+                       run_modeset_transition(&test_config, i, false, true);
 
                igt_subtest_f("%ix-modeset-transitions-nonblocking-fencing", i)
-                       run_modeset_transition(&display, i, true, true);
+                       run_modeset_transition(&test_config, i, true, true);
        }
 
        igt_fixture {
                igt_display_fini(&display);
        }
+
+       igt_exit();
 }
-- 
2.13.2

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to