Skip to content

Commit

Permalink
sched_football: Rewrite into new API
Browse files Browse the repository at this point in the history
This is due test compilation broken on old gcc 4.8 we still support
since 8fc3cf4.

Combining LTP librealtime (librttest.c) and LTP library is somehow
experimental. -lltp was needed to be added to CFLAGS.

librttest.c getopts were ignored, port just test specific -l and -n.

Fixes: 8fc3cf4 ("sched_football: Re-add the crazy fans to interrupt everyone")
Link: https://lore.kernel.org/ltp/20240711104400.63355-2-pvorel@suse.cz/
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
Signed-off-by: Petr Vorel <pvorel@suse.cz>
  • Loading branch information
pevik committed Jul 17, 2024
1 parent 5da10a3 commit 43dc52f
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 145 deletions.
27 changes: 7 additions & 20 deletions testcases/realtime/func/sched_football/Makefile
Original file line number Diff line number Diff line change
@@ -1,28 +1,15 @@
#
# realtime/func/sched_football test suite Makefile.
#
# Copyright (C) 2009, Cisco Systems Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2009, Cisco Systems Inc.
# Copyright (c) Linux Test Project, 2009-2024
# realtime/func/sched_football test suite Makefile.
# Ngie Cooper, September 2009
#

top_srcdir ?= ../../../..

INSTALL_TARGETS := run_auto.sh
include $(top_srcdir)/include/mk/env_pre.mk
include $(abs_srcdir)/../../config.mk

# TODO: integrate properly with LTP library
LDLIBS += -lltp
include $(top_srcdir)/include/mk/generic_leaf_target.mk
204 changes: 79 additions & 125 deletions testcases/realtime/func/sched_football/sched_football.c
Original file line number Diff line number Diff line change
@@ -1,125 +1,58 @@
/******************************************************************************
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright © International Business Machines Corp., 2007, 2008
* Copyright (c) 2024 Petr Vorel <pvorel@suse.cz>
* Author: John Stultz <jstultz@google.com>
*/

/*\
* [Description]
*
* Copyright © International Business Machines Corp., 2007, 2008
* Scheduler test that uses a football analogy.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* The premise is that we want to make sure that lower priority threads
* don't run while we have runnable higher priority threads.
* The offense is trying to increment the balls position, while the
* defense is trying to block that from happening.
* And the ref (highest priority thread) will blow the wistle if the
* ball moves. Finally, we have crazy fans (higer prority) that try to
* distract the defense by occasionally running onto the field.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
* [Algorithm]
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* NAME
* sched_football.c
*
* DESCRIPTION
* This is a scheduler test that uses a football analogy.
* The premise is that we want to make sure that lower priority threads
* don't run while we have runnable higher priority threads.
* The offense is trying to increment the balls position, while the
* defense is trying to block that from happening.
* And the ref (highest priority thread) will blow the wistle if the
* ball moves. Finally, we have crazy fans (higer prority) that try to
* distract the defense by occasionally running onto the field.
*
* Steps:
* - Create NR_CPU offense threads (lower priority)
* - Create NR_CPU defense threads (mid priority)
* - Create 2*NR_CPU fan threads (high priority)
* - Create a referee thread (highest priority)
* - Once everyone is on the field, the offense thread spins incrementing
* the value of 'the_ball'. The defense thread tries to block the ball
* by never letting the offense players get the CPU (it just spins).
* The crazy fans sleep a bit, then jump the rail and run across the
* field, disrupting the players on the field.
* - The refree threads wakes up regularly to check if the game is over :)
* - In the end, if the value of 'the_ball' is >0, the test is considered
* to have failed.
*
* USAGE:
* Use run_auto.sh script in current directory to build and run test.
*
* AUTHOR
* John Stultz <johnstul@xxxxxxxxx >
*
* HISTORY
* 2006-03-16 Reduced verbosity, non binary failure reporting, removal of
* crazy_fans thread, added game_length argument by Darren Hart.
* 2007-08-01 Remove all thread cleanup in favor of simply exiting.Various
* bugfixes and cleanups. -- Josh Triplett
* 2009-06-23 Simplified atomic startup mechanism, avoiding thundering herd
* scheduling at the beginning of the game. -- Darren Hart
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <sched.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
* - Create NR_CPU offense threads (lower priority).
* - Create NR_CPU defense threads (mid priority).
* - Create 2*NR_CPU fan threads (high priority).
* - Create a referee thread (highest priority).
* - Once everyone is on the field, the offense thread spins incrementing
* the value of 'the_ball'. The defense thread tries to block 'the_ball'
* by never letting the offense players get the CPU (it just spins).
* The crazy fans sleep a bit, then jump the rail and run across the
* field, disrupting the players on the field.
* - The refree threads wakes up regularly to check if the game is over :).
* - If the value of 'the_ball' is > 0, the test is considered to have failed.
*/

#include <sys/prctl.h>
#include <sys/time.h>
#include <librttest.h>
#include <tst_atomic.h>
#define TST_NO_DEFAULT_MAIN
#include <tst_timer.h>

#include "librttest.h"
#include "tst_test.h"

#define DEF_GAME_LENGTH 5
#define SPIN_TIME_NS 200000000ULL
#define SLEEP_TIME_NS 50000000ULL

/* Here's the position of the ball */
static int the_ball;

static int players_per_team = 0;
static int game_length = DEF_GAME_LENGTH;
static int players_ready;

void usage(void)
{
rt_help();
printf("sched_football specific options:\n");
printf(" -nPLAYERS players per team (defaults to num_cpus)\n");
printf(" -lGAME_LENGTH game length in seconds (defaults to %d s)\n",
DEF_GAME_LENGTH);
}

int parse_args(int c, char *v)
{

int handled = 1;
switch (c) {
case 'h':
usage();
exit(0);
case 'n':
players_per_team = atoi(v);
break;
case 'l':
game_length = atoi(v);
break;
default:
handled = 0;
break;
}
return handled;
}
static char *str_game_length;
static char *str_players_per_team;

#define SPIN_TIME_NS 200000000ULL
#define SLEEP_TIME_NS 50000000ULL
/* These are fans running across the field. They're trying to interrupt/distract everyone */
void *thread_fan(void *arg)
void *thread_fan(void *arg LTP_ATTRIBUTE_UNUSED)
{
prctl(PR_SET_NAME, "crazy_fan", 0, 0, 0);
tst_atomic_add_return(1, &players_ready);
Expand All @@ -139,38 +72,43 @@ void *thread_fan(void *arg)
nsec = tst_timespec_diff_ns(stop, start);
}
}

return NULL;
}

/* This is the defensive team. They're trying to block the offense */
void *thread_defense(void *arg)
void *thread_defense(void *arg LTP_ATTRIBUTE_UNUSED)
{
prctl(PR_SET_NAME, "defense", 0, 0, 0);
tst_atomic_add_return(1, &players_ready);
/*keep the ball from being moved */
while (1) {
}

return NULL;
}

/* This is the offensive team. They're trying to move the ball */
void *thread_offense(void *arg)
void *thread_offense(void *arg LTP_ATTRIBUTE_UNUSED)
{
prctl(PR_SET_NAME, "offense", 0, 0, 0);
tst_atomic_add_return(1, &players_ready);
while (1) {
tst_atomic_add_return(1, &the_ball); /* move the ball ahead one yard */
}

return NULL;
}

int referee(int game_length)
void referee(int game_length)
{
struct timeval start, now;
int final_ball;

tst_res(TINFO, "Starting referee thread");

prctl(PR_SET_NAME, "referee", 0, 0, 0);
printf("Game On (%d seconds)!\n", game_length);
tst_res(TINFO, "Starting the game (%d sec)", game_length);

/* open trace marker early to avoid latency with the first message */
trace_marker_prep();
Expand All @@ -188,28 +126,25 @@ int referee(int game_length)
}
atrace_marker_write("sched_football", "Game_Over!");
final_ball = tst_atomic_load(&the_ball);

/* Blow the whistle */
printf("Game Over!\n");
printf("Final ball position: %d\n", final_ball);
return final_ball != 0;
tst_res(TINFO, "Final ball position: %d", final_ball);

TST_EXP_EXPR(final_ball == 0);
}

int main(int argc, char *argv[])
static void do_test(void)
{
struct sched_param param;
int priority;
int i;
int result;
setup();

rt_init("n:l:h", parse_args, argc, argv);

if (players_per_team == 0)
players_per_team = sysconf(_SC_NPROCESSORS_ONLN);

tst_atomic_store(0, &players_ready);

printf("Running with: players_per_team=%d game_length=%d\n",
tst_res(TINFO, "players_per_team: %d game_length: %d",
players_per_team, game_length);

/* We're the ref, so set our priority right */
Expand All @@ -221,7 +156,7 @@ int main(int argc, char *argv[])
* They are lower priority than defense, so they must be started first.
*/
priority = 15;
printf("Starting %d offense threads at priority %d\n",
tst_res(TINFO, "Starting %d offense threads at priority %d",
players_per_team, priority);
for (i = 0; i < players_per_team; i++)
create_fifo_thread(thread_offense, NULL, priority);
Expand All @@ -232,7 +167,7 @@ int main(int argc, char *argv[])

/* Start the defense */
priority = 30;
printf("Starting %d defense threads at priority %d\n",
tst_res(TINFO, "Starting %d defense threads at priority %d",
players_per_team, priority);
for (i = 0; i < players_per_team; i++)
create_fifo_thread(thread_defense, NULL, priority);
Expand All @@ -243,7 +178,7 @@ int main(int argc, char *argv[])

/* Start the crazy fans*/
priority = 50;
printf("Starting %d fan threads at priority %d\n",
tst_res(TINFO, "Starting %d fan threads at priority %d",
players_per_team, priority);
for (i = 0; i < players_per_team*2; i++)
create_fifo_thread(thread_fan, NULL, priority);
Expand All @@ -255,9 +190,28 @@ int main(int argc, char *argv[])
/* let things get into steady state */
sleep(2);
/* Ok, everyone is on the field, bring out the ref */
printf("Starting referee thread\n");
result = referee(game_length);
printf("Result: %s\n", result ? "FAIL" : "PASS");
return result;

referee(game_length);
}

static void do_setup(void)
{
if (tst_parse_int(str_game_length, &game_length, 1, INT_MAX))
tst_brk(TBROK, "Invalid game length '%s'", str_game_length);

if (tst_parse_int(str_players_per_team, &players_per_team, 1, INT_MAX))
tst_brk(TBROK, "Invalid number of players '%s'", str_players_per_team);
}

static struct tst_test test = {
.test_all = do_test,
.setup = do_setup,
.needs_root = 1,
.options = (struct tst_option[]) {
{"l:", &str_game_length, "Game length in sec (default: "
TST_TO_STR(DEF_GAME_LENGTH) " sec)"},
{"n:", &str_players_per_team,
"Number of players (default: number of CPU)"},
{}
},
};

0 comments on commit 43dc52f

Please sign in to comment.