mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
tests/clutter/timeline-interpolate: Rework test to be less flaky
This more or less rewrites this test so that it explicitly tests the "interpolation" when a timeline loops, i.e. that if something occupies the thread when a timeline was supposed to have looped, we end up in the right place "in the middle" of the next timeline cycle. The test more or less does this: * Start a 3 second looping timeline * Sleep so that we're in the middle of the first cycle * Sleep again so that we end up in the middle of the next cycle The semantics checked are that we see the following frames: * The first frame with timestamp 0 * The second frame in the middle of the first cycle (timestamp ~= 1.5 sceonds) * The third frame in the end of the first cycle (timestamp == 3.0 seconds) * The fourth frame, first in the second cycle, with timestamp ~= 1.5 seconds) This means we can increase the "grace period" to the double (from 0.5 s to 1 s), while at the same time decrease the time spent running the test (from 10 s to 4.5 s). This should hopefully make the test less flaky, especially in slower runners, e.g. aarch64. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1751>
This commit is contained in:
parent
0d3840b056
commit
6f30764320
@ -5,21 +5,13 @@
|
||||
|
||||
#include "tests/clutter-test-utils.h"
|
||||
|
||||
/* We ask for 1 frame per millisecond.
|
||||
* Whenever this rate can't be achieved then the timeline
|
||||
* will interpolate the number frames that should have
|
||||
* passed between timeouts. */
|
||||
#define TEST_TIMELINE_FPS 1000
|
||||
#define TEST_TIMELINE_DURATION 5000
|
||||
#define TEST_TIMELINE_DURATION 3000
|
||||
|
||||
/* We are at the mercy of the system scheduler so this
|
||||
* may not be a very reliable tolerance.
|
||||
*
|
||||
* It's set as very tolerable (1 ms shorter than the frame interval) as
|
||||
* otherwise CI, which are very prone to not get CPU time scheduled, tend to
|
||||
* often fail.
|
||||
/*
|
||||
* Make the test tolarate being half a second off track in each direction,
|
||||
* the thing we're testing for will still be tested for.
|
||||
*/
|
||||
#define TEST_ERROR_TOLERANCE ((TEST_TIMELINE_FPS / 4) - 1)
|
||||
#define TEST_ERROR_TOLERANCE 500
|
||||
|
||||
typedef struct _TestState
|
||||
{
|
||||
@ -28,7 +20,7 @@ typedef struct _TestState
|
||||
int new_frame_counter;
|
||||
int expected_frame;
|
||||
int completion_count;
|
||||
gboolean passed;
|
||||
int cycle_frame_counter;
|
||||
} TestState;
|
||||
|
||||
|
||||
@ -41,7 +33,6 @@ new_frame_cb (ClutterTimeline *timeline,
|
||||
int current_frame;
|
||||
long msec_diff;
|
||||
int loop_overflow = 0;
|
||||
static int step = 1;
|
||||
|
||||
current_time = g_get_real_time ();
|
||||
|
||||
@ -61,8 +52,12 @@ new_frame_cb (ClutterTimeline *timeline,
|
||||
state->expected_frame = TEST_TIMELINE_DURATION;
|
||||
}
|
||||
|
||||
if (current_frame >= (state->expected_frame-TEST_ERROR_TOLERANCE)
|
||||
&& current_frame <= (state->expected_frame+TEST_ERROR_TOLERANCE))
|
||||
switch (state->cycle_frame_counter)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
if (current_frame >= (state->expected_frame - TEST_ERROR_TOLERANCE) &&
|
||||
current_frame <= (state->expected_frame + TEST_ERROR_TOLERANCE))
|
||||
{
|
||||
g_test_message ("elapsed milliseconds=%-5li "
|
||||
"expected frame=%-4i actual frame=%-4i (OK)",
|
||||
@ -77,41 +72,80 @@ new_frame_cb (ClutterTimeline *timeline,
|
||||
msec_diff,
|
||||
state->expected_frame,
|
||||
current_frame);
|
||||
state->passed = FALSE;
|
||||
g_test_fail ();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
g_assert_cmpint (current_frame, ==, TEST_TIMELINE_DURATION);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (step>0)
|
||||
/* We already tested that we interpolated when looping, lets stop now. */
|
||||
if (state->completion_count == 1 &&
|
||||
state->cycle_frame_counter == 0)
|
||||
{
|
||||
state->expected_frame = current_frame + (TEST_TIMELINE_FPS / 4);
|
||||
g_test_message ("Sleeping for 250ms "
|
||||
"so next frame should be (%i + %i) = %i",
|
||||
current_frame,
|
||||
(TEST_TIMELINE_FPS / 4),
|
||||
state->expected_frame);
|
||||
g_usleep (250000);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->expected_frame = current_frame + TEST_TIMELINE_FPS;
|
||||
g_test_message ("Sleeping for 1sec "
|
||||
"so next frame should be (%i + %i) = %i",
|
||||
current_frame,
|
||||
TEST_TIMELINE_FPS,
|
||||
state->expected_frame);
|
||||
g_usleep (1000000);
|
||||
clutter_timeline_stop (timeline);
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_frame >= TEST_TIMELINE_DURATION)
|
||||
switch (state->cycle_frame_counter)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
/*
|
||||
* First frame, sleep so we're about in the middle of the cycle,
|
||||
* before the end of the timeline cycle.
|
||||
*/
|
||||
int delay_ms = ms (1500);
|
||||
|
||||
state->expected_frame = current_frame + delay_ms;
|
||||
g_test_message ("Sleeping for 1.5 seconds "
|
||||
"so next frame should be (%d + %d) = %d",
|
||||
current_frame,
|
||||
delay_ms,
|
||||
state->expected_frame);
|
||||
g_usleep (ms2us (delay_ms));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
/*
|
||||
* Second frame, we're about in the middle of the cycle; sleep one cycle,
|
||||
* and check that we end up in the middle again.
|
||||
*/
|
||||
int delay_ms = TEST_TIMELINE_DURATION;
|
||||
|
||||
state->expected_frame = current_frame + delay_ms;
|
||||
g_test_message ("Sleeping for %d seconds "
|
||||
"so next frame should be (%d + %d) = %d, "
|
||||
"which is %d into the next cycle",
|
||||
TEST_TIMELINE_DURATION / 1000,
|
||||
current_frame,
|
||||
delay_ms,
|
||||
state->expected_frame,
|
||||
state->expected_frame - TEST_TIMELINE_DURATION);
|
||||
g_usleep (ms2us (delay_ms));
|
||||
|
||||
g_assert_cmpint (state->expected_frame, >, TEST_TIMELINE_DURATION);
|
||||
|
||||
state->expected_frame += loop_overflow;
|
||||
state->expected_frame -= TEST_TIMELINE_DURATION;
|
||||
g_test_message ("End of timeline reached: "
|
||||
"Wrapping expected frame too %i",
|
||||
"Wrapping expected frame too %d",
|
||||
state->expected_frame);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
state->new_frame_counter++;
|
||||
step = -step;
|
||||
state->cycle_frame_counter++;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -119,14 +153,20 @@ completed_cb (ClutterTimeline *timeline,
|
||||
TestState *state)
|
||||
{
|
||||
state->completion_count++;
|
||||
state->cycle_frame_counter = 0;
|
||||
|
||||
if (state->completion_count == 2)
|
||||
{
|
||||
if (state->passed)
|
||||
clutter_test_quit ();
|
||||
else
|
||||
if (state->completion_count >= 2)
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
stopped_cb (ClutterTimeline *timeline,
|
||||
gboolean is_finished,
|
||||
TestState *state)
|
||||
{
|
||||
g_assert_cmpint (state->completion_count, ==, 1);
|
||||
|
||||
clutter_test_quit ();
|
||||
}
|
||||
|
||||
static void
|
||||
@ -148,10 +188,14 @@ timeline_interpolation (void)
|
||||
"completed",
|
||||
G_CALLBACK (completed_cb),
|
||||
&state);
|
||||
g_signal_connect (state.timeline,
|
||||
"stopped",
|
||||
G_CALLBACK (stopped_cb),
|
||||
&state);
|
||||
|
||||
state.completion_count = 0;
|
||||
state.new_frame_counter = 0;
|
||||
state.passed = TRUE;
|
||||
state.cycle_frame_counter = 0;
|
||||
state.expected_frame = 0;
|
||||
|
||||
clutter_actor_show (stage);
|
||||
|
Loading…
Reference in New Issue
Block a user