Home | History | Annotate | Download | only in sched_football
      1 /******************************************************************************
      2  *
      3  *   Copyright  International Business Machines  Corp., 2007, 2008
      4  *
      5  *   This program is free software;  you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 2 of the License, or
      8  *   (at your option) any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  *   the GNU General Public License for more details.
     14  *
     15  *   You should have received a copy of the GNU General Public License
     16  *   along with this program;  if not, write to the Free Software
     17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     18  *
     19  * NAME
     20  *      sched_football.c
     21  *
     22  * DESCRIPTION
     23  *      This is a scheduler test that uses a football analogy.
     24  *      The premise is that we want to make sure that lower priority threads
     25  *      (defensive team). The offense is trying to increment the balls position,
     26  *      while the defense is trying to block that from happening.
     27  *      And the ref (highest priority thread) will blow the wistle if the
     28  *      ball moves. Finally, we have crazy fans (higer prority) that try to
     29  *      distract the defense by occasionally running onto the field.
     30  *
     31  *      Steps:
     32  *       - Create a fixed number of offense threads (lower priority)
     33  *       - Create a referee thread (highest priority)
     34  *       - Once everyone is on the field, the offense thread increments the
     35  *	 value of 'the_ball' and yields. The defense thread tries to block
     36  *	 the ball by never letting the offense players get the CPU (it just
     37  * 	   does a sched_yield).
     38  *       - The refree threads wakes up regularly to check if the game is over :)
     39  *       - In the end, if the value of 'the_ball' is >0, the test is considered
     40  *	 to have failed.
     41  *
     42  * USAGE:
     43  *      Use run_auto.sh script in current directory to build and run test.
     44  *
     45  * AUTHOR
     46  *      John Stultz <johnstul@xxxxxxxxx >
     47  *
     48  * HISTORY
     49  *     2006-03-16 Reduced verbosity, non binary failure reporting, removal of
     50  *		crazy_fans thread, added game_length argument by Darren Hart.
     51  *     2007-08-01 Remove all thread cleanup in favor of simply exiting.Various
     52  *		bugfixes and cleanups. -- Josh Triplett
     53  *     2009-06-23 Simplified atomic startup mechanism, avoiding thundering herd
     54  *		scheduling at the beginning of the game. -- Darren Hart
     55  *
     56  *****************************************************************************/
     57 
     58 #include <stdio.h>
     59 #include <stdlib.h>
     60 #include <signal.h>
     61 #include <time.h>
     62 #include <string.h>
     63 #include <pthread.h>
     64 #include <sched.h>
     65 #include <errno.h>
     66 #include <sys/syscall.h>
     67 #include <unistd.h>
     68 #include <sys/time.h>
     69 #include <librttest.h>
     70 
     71 #define DEF_GAME_LENGTH 5
     72 
     73 /* Here's the position of the ball */
     74 volatile int the_ball;
     75 
     76 static int players_per_team = 0;
     77 static int game_length = DEF_GAME_LENGTH;
     78 static atomic_t players_ready;
     79 
     80 void usage(void)
     81 {
     82 	rt_help();
     83 	printf("sched_football specific options:\n");
     84 	printf("  -nPLAYERS     players per team (defaults to num_cpus)\n");
     85 	printf("  -lGAME_LENGTH game length in seconds (defaults to %d s)\n",
     86 	       DEF_GAME_LENGTH);
     87 }
     88 
     89 int parse_args(int c, char *v)
     90 {
     91 
     92 	int handled = 1;
     93 	switch (c) {
     94 	case 'h':
     95 		usage();
     96 		exit(0);
     97 	case 'n':
     98 		players_per_team = atoi(v);
     99 		break;
    100 	case 'l':
    101 		game_length = atoi(v);
    102 		break;
    103 	default:
    104 		handled = 0;
    105 		break;
    106 	}
    107 	return handled;
    108 }
    109 
    110 /* This is the defensive team. They're trying to block the offense */
    111 void *thread_defense(void *arg)
    112 {
    113 	atomic_inc(&players_ready);
    114 	/*keep the ball from being moved */
    115 	while (1) {
    116 		sched_yield();	/* let other defenders run */
    117 	}
    118 	return NULL;
    119 }
    120 
    121 /* This is the offensive team. They're trying to move the ball */
    122 void *thread_offense(void *arg)
    123 {
    124 	atomic_inc(&players_ready);
    125 	while (1) {
    126 		the_ball++;	/* move the ball ahead one yard */
    127 		sched_yield();	/* let other offensive players run */
    128 	}
    129 	return NULL;
    130 }
    131 
    132 int referee(int game_length)
    133 {
    134 	struct timeval start, now;
    135 	int final_ball;
    136 
    137 	printf("Game On (%d seconds)!\n", game_length);
    138 
    139 	gettimeofday(&start, NULL);
    140 	now = start;
    141 
    142 	/* Start the game! */
    143 	the_ball = 0;
    144 
    145 	/* Watch the game */
    146 	while ((now.tv_sec - start.tv_sec) < game_length) {
    147 		sleep(1);
    148 		gettimeofday(&now, NULL);
    149 	}
    150 	/* Blow the whistle */
    151 	printf("Game Over!\n");
    152 	final_ball = the_ball;
    153 	printf("Final ball position: %d\n", final_ball);
    154 	return final_ball != 0;
    155 }
    156 
    157 int main(int argc, char *argv[])
    158 {
    159 	struct sched_param param;
    160 	int priority;
    161 	int i;
    162 	int result;
    163 	setup();
    164 
    165 	rt_init("n:l:h", parse_args, argc, argv);
    166 
    167 	if (players_per_team == 0)
    168 		players_per_team = sysconf(_SC_NPROCESSORS_ONLN);
    169 
    170 	atomic_set(0, &players_ready);
    171 
    172 	printf("Running with: players_per_team=%d game_length=%d\n",
    173 	       players_per_team, game_length);
    174 
    175 	/* We're the ref, so set our priority right */
    176 	param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 80;
    177 	sched_setscheduler(0, SCHED_FIFO, &param);
    178 
    179 	/*
    180 	 * Start the offense
    181 	 * They are lower priority than defense, so they must be started first.
    182 	 */
    183 	priority = 15;
    184 	printf("Starting %d offense threads at priority %d\n",
    185 	       players_per_team, priority);
    186 	for (i = 0; i < players_per_team; i++)
    187 		create_fifo_thread(thread_offense, NULL, priority);
    188 
    189 	/* Wait for the offense threads to start */
    190 	while (atomic_get(&players_ready) < players_per_team)
    191 		usleep(100);
    192 
    193 	/* Start the defense */
    194 	priority = 30;
    195 	printf("Starting %d defense threads at priority %d\n",
    196 	       players_per_team, priority);
    197 	for (i = 0; i < players_per_team; i++)
    198 		create_fifo_thread(thread_defense, NULL, priority);
    199 
    200 	/* Wait for the defense threads to start */
    201 	while (atomic_get(&players_ready) < players_per_team * 2)
    202 		usleep(100);
    203 
    204 	/* Ok, everyone is on the field, bring out the ref */
    205 	printf("Starting referee thread\n");
    206 	result = referee(game_length);
    207 	printf("Result: %s\n", result ? "FAIL" : "PASS");
    208 	return result;
    209 
    210 }
    211