[LTP] [PATCH v2] sched_football: synchronize with kickoff flag to reduce skew
Li Wang
liwang@redhat.com
Fri Sep 5 13:50:22 CEST 2025
On Fri, Sep 5, 2025 at 5:18 PM Cyril Hrubis <chrubis@suse.cz> wrote:
> Hi!
> > Checking the configurations of the stock kernel and the real-time
> > kernel, the stock kernel uses "CONFIG_PREEMPT_VOLUNTARY=y,"
> > which only provides voluntary preemption.
> >
> > This preemption model is designed to strike a balance between throughput
> > and latency. It only allows the kernel to be preempted at specific, well
> > defined
> > "safe points," potentially resulting in long, unbounded latencies.
> >
> > However, the sched_football test was most likely designed to measure or
> > stress-test the deterministic, low-latency scheduling behavior that is
> > characteristic of real-time (RT) kernel.
> >
> > So, I tend to believe the test's failure on the stock kernel is
> acceptable.
>
> I still find it a bit unexpected though. The preeption models apply only
> to kernel code. The user space code can be stil preempted at any point,
> so the offense threads should be preempted and replaced by high priority
> tasks and never executed again since we do not call to the kernel there
> at all, we just run a loop that increments an integer there. I guess
> that one possibility is that we saturate the machine with real-time
> tasks to the extend that scheduller code in kernel does not get to
> distribute the processes. If that is a problem we need to give kernel
> chance to shuffle the processes when we wait for the kickoff flag.
>
> Does things start to work if we change the loops that wait for the final
> kickoff to:
>
> while (!tst_atomic_load(&kickoff_flag))
> sched_yield();
>
This has improved something, but still observes sporadic fail on RHEL stock
kernel.
However, both the RHEL RT-kernel and the mainline v6.17-rc4 stock kernel
pass.
Below is my complete test patch, can you guys try it on SUSE stock kernel?
--- a/testcases/realtime/func/sched_football/sched_football.c
+++ b/testcases/realtime/func/sched_football/sched_football.c
@@ -44,6 +44,7 @@
static tst_atomic_t the_ball;
static int players_per_team = 0;
static int game_length = DEF_GAME_LENGTH;
+static tst_atomic_t kickoff_flag;
static tst_atomic_t game_over;
static char *str_game_length;
@@ -55,6 +56,9 @@ void *thread_fan(void *arg LTP_ATTRIBUTE_UNUSED)
{
prctl(PR_SET_NAME, "crazy_fan", 0, 0, 0);
pthread_barrier_wait(&start_barrier);
+ while (!tst_atomic_load(&kickoff_flag))
+ sched_yield();
+
/*occasionally wake up and run across the field */
while (!tst_atomic_load(&game_over)) {
struct timespec start, stop;
@@ -80,6 +84,9 @@ void *thread_defense(void *arg LTP_ATTRIBUTE_UNUSED)
{
prctl(PR_SET_NAME, "defense", 0, 0, 0);
pthread_barrier_wait(&start_barrier);
+ while (!tst_atomic_load(&kickoff_flag))
+ sched_yield();
+
/*keep the ball from being moved */
while (!tst_atomic_load(&game_over)) {
}
@@ -92,6 +99,9 @@ void *thread_offense(void *arg LTP_ATTRIBUTE_UNUSED)
{
prctl(PR_SET_NAME, "offense", 0, 0, 0);
pthread_barrier_wait(&start_barrier);
+ while (!tst_atomic_load(&kickoff_flag))
+ sched_yield();
+
while (!tst_atomic_load(&game_over)) {
tst_atomic_add_return(1, &the_ball); /* move the ball ahead
one yard */
}
@@ -115,9 +125,15 @@ void referee(int game_length)
now = start;
/* Start the game! */
- tst_atomic_store(0, &the_ball);
- pthread_barrier_wait(&start_barrier);
atrace_marker_write("sched_football", "Game_started!");
+ pthread_barrier_wait(&start_barrier);
+ tst_atomic_store(0, &the_ball);
+ tst_atomic_store(1, &kickoff_flag);
+
+ if (tst_check_preempt_rt())
+ usleep(20000);
+ else
+ usleep(2000000);
/* Watch the game */
while ((now.tv_sec - start.tv_sec) < game_length) {
@@ -125,14 +141,14 @@ void referee(int game_length)
gettimeofday(&now, NULL);
}
- /* Stop the game! */
- tst_atomic_store(1, &game_over);
- atrace_marker_write("sched_football", "Game_Over!");
-
/* Blow the whistle */
final_ball = tst_atomic_load(&the_ball);
tst_res(TINFO, "Final ball position: %d", final_ball);
+ /* Stop the game! */
+ tst_atomic_store(1, &game_over);
+ atrace_marker_write("sched_football", "Game_Over!");
+
TST_EXP_EXPR(final_ball == 0);
}
@@ -154,6 +170,7 @@ static void do_test(void)
/* We're the ref, so set our priority right */
param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 80;
sched_setscheduler(0, SCHED_FIFO, ¶m);
+ tst_atomic_store(0, &kickoff_flag);
/*
* Start the offense
> This should trigger the scheduller code to be executed so that it has
> chance to distribute the processes around.
>
> --
> Cyril Hrubis
> chrubis@suse.cz
>
>
--
Regards,
Li Wang
More information about the ltp
mailing list