• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
usage(void)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 
parse_args(int c,char * v)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 */
thread_defense(void * arg)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 */
thread_offense(void * arg)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 
referee(int game_length)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 
main(int argc,char * argv[])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