1 /*
2  *   Copyright (c) International Business Machines  Corp., 2001
3  *
4  *   This program is free software;  you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12  *   the GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program;  if not, write to the Free Software
16  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 /*---------------------------------------------------------------------+
19 |                             sched_driver                             |
20 | ==================================================================== |
21 |                                                                      |
22 | Description:  This program uses system calls to change the           |
23 |               priorities of the throughput measurement testcases.    |
24 |               When real-time is in effect, priorities 50 through 64  |
25 |               are used.  (MAX_PRI and MIN_PRI)  When user-time       |
26 |               (normal) is in effect, 0-14 (corresponding to nice()   |
27 |               calls) is used.  The driver only keeps track of        |
28 |               values from 50 to 64, and the testcases will scale     |
29 |               them down to 0 to 14 when needed, to change the        |
30 |               priority of a user-time process.                       |
31 |                                                                      |
32 | Algorithm:    o  Parse command line arguments                        |
33 |               o  Set current priority                                |
34 |               o  Calcucations (process slots, short/long term slots) |
35 |               o  Perform throughput tests with high priority         |
36 |               o  Start long-term testcases                           |
37 |               o  While time remains                                  |
38 |                  - Start short-term tests                            |
39 |                  - Perform throughput tests with new priority        |
40 |                  - Kill short-term tests                             |
41 |                  - Increase priority                                 |
42 |                                                                      |
43 | Usage:        sched_driver [-s n] [-p n] [-t n] [-d] [-v]            |
44 |                                                                      |
45 |               where:                                                 |
46 |                 -s n  stress percentage                              |
47 |                 -p n  process slots                                  |
48 |                 -t n  execution time in hours                        |
49 |                 -d    enable debugging messages                      |
50 |                 -v    Turn on verbose mode                           |
51 |                                                                      |
52 | Last update:   Ver. 1.15, 4/10/94 23:04:23                           |
53 |                                                                      |
54 | Change Activity                                                      |
55 |                                                                      |
56 |   Version  Date    Name  Reason                                      |
57 |    0.1     072889  GEB   Initial draft                               |
58 |    1.2     120793  JAT   Changes for AIX 4.1                         |
59 |    1.3     041094  DJK   Rewrote protions...                         |
60 |    1.4     010402  Manoj Iyer Ported to Linux                        |
61 |                                                                      |
62 +---------------------------------------------------------------------*/
63 
64 #include <sys/types.h>
65 #include <unistd.h>
66 #include <sys/wait.h>
67 #include <string.h>
68 #include <stdlib.h>
69 #include <signal.h>
70 #include <pwd.h>
71 #include <time.h>
72 #include <limits.h>
73 #include "sched.h"
74 
75 /*
76  * Defines:
77  *
78  * MAXPROCS: maximum number of processes
79  *
80  * PRIINC: priority step value
81  *
82  * MAX_PRI: highest priority to use
83  *
84  * MIN_PRI: lowest priority to use
85  *
86  * DEFAULT_STRESS_PERCENTAGE: stress percentage (process slot multiplier)
87  *
88  * DEFAULT_PROCESS_SLOTS: number of processes test driver will try and create
89  *
90  * DEFAULT_TIME: time (hours) for which this test driver will run
91  *
92  * USAGE: usage statement
93  */
94 #define MAXPROCS   100
95 #define PRIINC     2
96 #define MAX_PRI    55		/* was 50 */
97 #define MIN_PRI    75		/* was 64 */
98 #define DEFAULT_STRESS_PERCENTAGE	0.5
99 #define DEFAULT_PROCESS_SLOTS		16
100 #define DEFAULT_TIME			1.00
101 #define USAGE "Usage:  %s  [-s n] [-p n] [-t n] [-d] [-v]              \n" \
102               "        -s n   stress percentage [0.0<n<1.0] (default 0.5) \n" \
103               "        -p n   process slots (default 16)                  \n" \
104               "        -t n   execution time in hours (default 1.0 hrs)   \n" \
105               "        -d     enable debugging messages                   \n" \
106               "        -v     Turn on verbose mode 	                  \n"
107 
108 /*
109  * Global variables:
110  *
111  * stress_percent: stress percentage
112  *
113  * :
114  *
115  * execution_time: execution time in hours
116  *
117  * debug: (option flag) enables debugging messages
118  */
119 int numprocs,			/* number of process id's in table             */
120  procs[MAXPROCS],		/* array of process id's for killing           */
121  long_running,			/* number of long term testcases running       */
122  short_running;			/* number of short term testcases running      */
123 float e4user,			/* previous elapsed seconds for tc 4-user      */
124  e4real,			/* previous elapsed seconds for tc 4-real      */
125  e5user,			/* previous elapsed seconds for tc 5-user      */
126  e5real,			/* previous elapsed seconds for tc 5-real      */
127  e6user0,			/* previous elapsed seconds for tc 6-user,nf   */
128  e6real0,			/* previous elapsed seconds for tc 6-real,nf   */
129  e6user1,			/* previous elapsed seconds for tc 6-user,f    */
130  e6child;			/* previous elapsed seconds for tc 6-child     */
131 double stress_percent = DEFAULT_STRESS_PERCENTAGE;
132 double execution_time = DEFAULT_TIME;
133 int process_slots = DEFAULT_PROCESS_SLOTS;
134 int debug = 0;
135 
136 /*
137  * Function prototypes
138  */
139 void startup(long);
140 int start_testcase(char *, char *, char *, char *, char *, char *);
141 int process_slots_in_use();
142 int available_user_process_slots();
143 float measure_test(char *, char *, char *, char *, float *);
144 void display_line(char *, int, int, float, float *, int);
145 void perform_throughput_tests(int);
146 void start_long_term_testcases(int, char *);
147 void kill_short_term_testcases();
148 void start_short_term_testcases(int, double, int);
149 void finishup(long);
150 void parse_args(int, char **);
151 
152 /*---------------------------------------------------------------------+
153 |                               main ()                                |
154 | ==================================================================== |
155 |                                                                      |
156 | Function:  Main program                                              |
157 |                                                                      |
158 +---------------------------------------------------------------------*/
main(int argc,char ** argv)159 int main(int argc, char **argv)
160 {
161 	long runseconds,	/* number of seconds to run */
162 	 start_time;		/* time at start of driver */
163 	int current_priority,	/* current priority level for nice */
164 	 workslots,		/* number of free workslots */
165 	 long_term_slot_total,	/* workslots for long-term processes */
166 	 short_term_slot_total;	/* workslots for short-term */
167 
168 	/*
169 	 * Parse command line arguments & printer program header...
170 	 */
171 	parse_args(argc, argv);
172 	printf("Scheduler Testsuite Program\n\n");
173 	fflush(stdout);
174 
175 	/*
176 	 * Calculate number of seconds to run, then print out start info
177 	 */
178 	runseconds = (long)(execution_time * 60.0 * 60.0);
179 	start_time = time(NULL);
180 
181 	startup(start_time);
182 
183 	/*
184 	 * Calculate available workslots, long-term, and short-term slots
185 	 */
186 	workslots = available_user_process_slots() * stress_percent;
187 	long_term_slot_total = workslots / 2;
188 	if (debug) {
189 		printf("available slots:      %d\n",
190 		       available_user_process_slots());
191 		printf("workslots available:  %d\n", workslots);
192 		printf("stress_percent:       %f\n", stress_percent);
193 		printf("run-hours:            %f (hrs)\n", execution_time);
194 		printf("runseconds:           %ld (sec)\n", runseconds);
195 	}
196 
197 	/*
198 	 * Run the first set of tests with an average priority
199 	 */
200 	perform_throughput_tests((MAX_PRI + MIN_PRI) / 2);
201 	fflush(stdout);
202 
203 	/*
204 	 * Start the long-term testcases running
205 	 */
206 	start_long_term_testcases(long_term_slot_total, argv[2]);
207 	short_term_slot_total = workslots / 2;
208 	fflush(stdout);
209 
210 	/*
211 	 * Loop while there is still time
212 	 */
213 	current_priority = MAX_PRI;
214 	while ((time(0) - start_time) < runseconds) {
215 
216 		if (debug)
217 			printf("current priority: %d\n", current_priority);
218 		if (debug)
219 			printf("starting short term tests\n");
220 
221 		start_short_term_testcases(short_term_slot_total,
222 					   stress_percent, current_priority);
223 		fflush(stdout);
224 
225 		perform_throughput_tests(current_priority);
226 		fflush(stdout);
227 
228 		if (debug)
229 			printf("killing short term tests\n");
230 
231 		kill_short_term_testcases();
232 		fflush(stdout);
233 
234 		if (current_priority + PRIINC > MIN_PRI)
235 			current_priority = MAX_PRI;
236 		else
237 			current_priority += PRIINC;
238 	}
239 
240 	/*
241 	 * Exit with success...
242 	 */
243 	finishup(start_time);
244 	printf("\nsuccessful!\n");
245 	fflush(stdout);
246 	return (0);
247 }
248 
249 /*------------------------------ startup() ------------------------------*/
250 /* This procedure opens the , and then outputs some starting	 *
251  * information to the screen and .  It also initializes the	 *
252  * process id list and other global variables.	 			 *
253  *-----------------------------------------------------------------------*/
startup(long start_time)254 void startup(long start_time)
255 {
256 	char tempbuffer[50];	/* temporary buffer to hold names */
257 
258 	/*
259 	 * Now output some diagnostic information
260 	 */
261 	printf("start time    = %s\n", ctime(&start_time));
262 
263 	gethostname(tempbuffer, 40);
264 	printf("host name     = %s\n", tempbuffer);
265 
266 	printf("user name     = %s\n", getpwuid(geteuid())->pw_name);
267 
268 	printf("test duration = %4.2f (hours)\n", execution_time);
269 
270 	printf("test stress   = %4.2f%%%%\n\n", 100 * stress_percent);
271 
272 	/*
273 	 * Initialize the global variables
274 	 */
275 	numprocs = 0;
276 	long_running = 0;
277 	short_running = 0;
278 	e4user = 0.0;
279 	e4real = 0.0;
280 	e5user = 0.0;
281 	e5real = 0.0;
282 	e6user0 = 0.0;
283 	e6real0 = 0.0;
284 	e6user1 = 0.0;
285 	e6child = 0.0;
286 }
287 
288 /*--------------------------- start_testcase() --------------------------*/
289 /* This procedure will run a specified testcase by forking a process, and*
290  * then running the testcase with it.  It will also store the process id *
291  * number in the process id table.  The process id of the child process  *
292  * is returned to the calling program.					 *
293  *	name1     pathname of testcase to run			         *
294  *	name2     filename of testcase to run			         *
295  *	param1    parameters to pass to the testcase			 *
296  *	param2 			         			         *
297  *	param3 			         			         *
298  *	param4    if sched_tc6:  fork flag:  0=false, 1=true             *
299  *-----------------------------------------------------------------------*/
300 
start_testcase(char * name1,char * name2,char * param1,char * param2,char * param3,char * param4)301 int start_testcase(char *name1, char *name2, char *param1, char *param2,
302 		   char *param3, char *param4)
303 {
304 	int pid,		/* pid of currently running process */
305 	 pid_save;		/* saved pid of process */
306 
307 	/*
308 	 * Fork a process that will run testcase and save the pid
309 	 */
310 	if (debug)
311 		printf("test: %s %s p1[%s] p2[%s] p3[%s] p4[%s]\n",
312 		       name1, name2, param1, param2, param3, param4);
313 
314 	pid_save = pid = fork();
315 
316 	/*
317 	 * If the pid returned is -1, fork failed.  If the pid returned is
318 	 * 0, then the process running is the child process, and we need
319 	 * to do an 'execl' to run the testcase.  If the pid returned is
320 	 * anything else, then the parent is running, and we return.
321 	 */
322 	switch (pid) {
323 	case -1:
324 		exit(-1);
325 	case 0:
326 		execl(name1, name2, param1, param2, param3, param4, NULL);
327 		printf("ERROR: start_testcase():  execl failed.\n");
328 		exit(-1);
329 	default:
330 		break;
331 	}
332 	if (debug)
333 		printf("testcase %s started -- pid is %d\n", name2, pid_save);
334 
335 	/*
336 	 * If the process just forked is for a short-term testcase, then
337 	 * add the process id to the table.
338 	 */
339 	if (debug)
340 		printf("new process: %s ", name2);
341 	if (strstr(name2, "tc1") || strstr(name2, "tc3")) {
342 		procs[numprocs] = pid_save;
343 		numprocs++;
344 		short_running++;
345 		if (debug)
346 			printf("(%d short term)", short_running);
347 	}
348 	if (strstr(name2, "tc0") || strstr(name2, "tc2")) {
349 		long_running++;
350 		if (debug)
351 			printf("(%d long term)", long_running);
352 	}
353 	if (debug)
354 		printf("\n");
355 
356 	return (pid_save);
357 }
358 
359 /*------------------------- process_slots_in_use() ----------------------*/
360 /* This function will return the number of process slots currently in use*
361  * by executing the 'ps' command.					 *
362  *-----------------------------------------------------------------------*/
process_slots_in_use()363 int process_slots_in_use()
364 {
365 	FILE *psfile;		/* temporary file to hold output of 'ps' command */
366 	int usedslots;		/* holds the number of used process slots */
367 
368 	/*
369 	 * Call the 'ps' command and write the number of process slots to a file
370 	 */
371 	if (system("ps -e | wc -l > ps.out") < 0)
372 		sys_error("system failed", __FILE__, __LINE__);
373 
374 	/*
375 	 * Open the output file
376 	 */
377 	if ((psfile = fopen("ps.out", "r")) == NULL) {
378 		exit(-1);
379 	}
380 
381 	/*
382 	 * Read the number of process slots in use from the file
383 	 */
384 	fscanf(psfile, "%d", &usedslots);
385 
386 	/*
387 	 * Close the output file
388 	 */
389 	if (fclose(psfile) == -1) {
390 		exit(-1);
391 	}
392 
393 	/*
394 	 * Remove the output file
395 	 */
396 	if (system("/bin/rm ps.out") < 0)
397 		sys_error("system failed", __FILE__, __LINE__);
398 
399 	return (usedslots - 1);
400 }
401 
402 /*----------------------- available_user_process_slots() ----------------*/
403 /* This function returns the total number of available user process slots*
404  * by subtracting the process slots currently in use from the maximum	 *
405  * possible process slots.						 *
406  *-----------------------------------------------------------------------*/
available_user_process_slots()407 int available_user_process_slots()
408 {
409 	int num = process_slots_in_use();
410 
411 	return ((process_slots < num) ? process_slots : process_slots - num);
412 }
413 
414 /*---------------------------- measure_test() ---------------------------*/
415 /* This function executes a throughput measurement process and waits for *
416  * that process to finish.  When finished, it reads the result from a 	 *
417  * file and returns that result to the caller.  The file is then deleted.*
418  * If sched_tc6 is called, then the second time is also read from the	 *
419  * results file and returned to the caller.				 *
420  *-----------------------------------------------------------------------*/
measure_test(name,param1,param2,param3,t2)421 float measure_test(name, param1, param2, param3, t2)
422 char *name,			/* filename of testcase to run */
423 *param1,			/* user flag:  0=user, 1=real time */
424 *param2,			/* priority to run the throughput test at */
425 *param3;			/* if sched_tc6:  fork flag, 0=false, 1=true */
426 float *t2;			/* if sched_tc6:  second time returned from testcase */
427 {
428 	char temp[PATH_MAX],	/* holds pathname and returned floating number */
429 	 t2asc[50];		/* holds second returned floating number */
430 	int saved_pid;		/* process id of forked process */
431 	FILE *datafile;		/* file pointer for temporary file */
432 
433 	/*
434 	 * Create the path name to be passed to the start_testcase() function
435 	 */
436 	sprintf(temp, "./%s", name);
437 
438 	/*
439 	 * Send all the parameters, and start the testcase
440 	 */
441 	saved_pid = start_testcase(temp, name, param1,
442 				   "-lsch.measure", param2, param3);
443 
444 	/*
445 	 * Wait for the testcase to finish
446 	 */
447 	if (debug)
448 		printf("waiting on child %d\n", saved_pid);
449 	while (wait(NULL) != saved_pid) ;
450 
451 	/*
452 	 * Open the temporary file to get the returned number of seconds
453 	 */
454 
455 	if ((datafile = fopen("sch.measure", "r")) == NULL) {
456 		sys_error("cannot open sch.measure", __FILE__, __LINE__);
457 	}
458 
459 	/*
460 	 * Read the number of seconds
461 	 */
462 	fgets(temp, 50, datafile);
463 	/*added by mpt
464 	   printf("sched+driver: measure_test: number of seconds=%s\n",temp)
465 	   *********** */
466 
467 	/*
468 	 * If this is sched_tc6, then there is another number we must return
469 	 */
470 
471 	if (strcmp(name, "sched_tc6") == 0) {
472 		fgets(t2asc, 50, datafile);
473 		*t2 = atof(t2asc);
474 	}
475 
476 	/*
477 	 * Close the temporary file
478 	 */
479 	if (fclose(datafile) != 0) {
480 		exit(-1);
481 	}
482 
483 	/*
484 	 * Now try to remove the temporary file
485 	 */
486 	/*added by MPT
487 	   printf("measure_test:  REMOVING sch.measure\n");
488 	   fflush(stdout);
489 	   if  (system ("rm sch.measure") < 0)
490 	   sys_error ("system failed", __FILE__, __LINE__);
491 	 */
492 	return (atof(temp));
493 }
494 
495 /*------------------------- display_line() ------------------------------*/
496 /* This procedure displays a line of output given the results of a	 *
497  * throughput test.  It displays the testcase name, the current priority *
498  * level, the user/real time flag, and the elapsed time in seconds, as	 *
499  * well as the percent change between the current and previous times.	 *
500  * It then updates the previous elapsed time to be the current one.	 *
501  *-----------------------------------------------------------------------*/
display_line(char * tcname,int pri,int f,float et,float * pet,int ff)502 void display_line(char *tcname, int pri, int f, float et, float *pet, int ff)
503 {
504 	static int display_header = 0;
505 	float pc;		/* holds percent change */
506 
507 	/*
508 	 * Print header every eight lines...
509 	 */
510 	if (display_header-- == 0) {
511 		printf("\n  Test                Processes              "
512 		       "  Time        Notes\n"
513 		       "---------   ---------------------------   "
514 		       "---------------  -------\n"
515 		       "name        long  short  priority  mode   "
516 		       "elapsed  %%%%delta\n\n");
517 		display_header = 6;
518 	}
519 
520 	/*
521 	 * Calculate the percent change in time
522 	 */
523 	pc = (*pet == 0.0) ? 0.0 : 100.0 * ((et - *pet) / *pet) + 0.05;
524 
525 	printf("%-12s %2d    %2d      %2d      %4s   %06.4f  %+06.4f  %s\n",
526 	       tcname, long_running, short_running, pri,
527 	       (f == 0) ? "user" : "real", et, pc, (ff) ? "forked child" : " ");
528 
529 	fflush(stdout);
530 
531 	*pet = et;
532 }
533 
534 /*------------------------- perform_throughput_tests() ------------------*/
535 /* This procedure is called each time throughput tests are to be	 *
536  * performed.  This procedure executes each of the throughput tests, and *
537  * records the results of each to the .	 			 *
538  *-----------------------------------------------------------------------*/
perform_throughput_tests(int current_priority)539 void perform_throughput_tests(int current_priority)
540 {
541 	float esecs,		/* elapsed seconds returned from each testcase */
542 	 esecs2,		/* elapsed seconds (second part) for sched_tc6 */
543 	 pc;			/* percent change for sched_tc6 */
544 	char pristr[10];	/* holds ascii value of priority as parameter */
545 
546 	sprintf(pristr, "-p%d", current_priority);
547 
548 #if defined(_IA64) && !defined(__64BIT__)
549 	esecs =
550 	    measure_test("sched_tc4.32", "-tvariable", pristr, NULL, &esecs2);
551 	display_line("sched_tc4.32", current_priority, 0, esecs, &e4user, 2);
552 	esecs = measure_test("sched_tc4.32", "-tfixed", pristr, NULL, &esecs2);
553 	display_line("sched_tc4.32", current_priority, 1, esecs, &e4real, 2);
554 	esecs =
555 	    measure_test("sched_tc5.32", "-tvariable", pristr, NULL, &esecs2);
556 	display_line("sched_tc5.32", current_priority, 0, esecs, &e5user, 2);
557 	esecs = measure_test("sched_tc5.32", "-tfixed", pristr, NULL, &esecs2);
558 	display_line("sched_tc5.32", current_priority, 1, esecs, &e5real, 2);
559 	esecs =
560 	    measure_test("sched_tc6.32", "-tvariable", pristr, " -d ", &esecs2);
561 	display_line("sched_tc6.32", current_priority, 0, esecs, &e6user0, 0);
562 	esecs =
563 	    measure_test("sched_tc6.32", "-tfixed", pristr, " -d ", &esecs2);
564 	display_line("sched_tc6.32", current_priority, 1, esecs, &e6real0, 0);
565 	esecs =
566 	    measure_test("sched_tc6.32", "-tvariable", pristr, " -df ",
567 			 &esecs2);
568 	display_line("sched_tc6.32", current_priority, 0, esecs, &e6user1, 1);
569 #else
570 	esecs = measure_test("sched_tc4", "-tvariable", pristr, NULL, &esecs2);
571 	display_line("sched_tc4", current_priority, 0, esecs, &e4user, 2);
572 	esecs = measure_test("sched_tc4", "-tfixed", pristr, NULL, &esecs2);
573 	display_line("sched_tc4", current_priority, 1, esecs, &e4real, 2);
574 	esecs = measure_test("sched_tc5", "-tvariable", pristr, NULL, &esecs2);
575 	display_line("sched_tc5", current_priority, 0, esecs, &e5user, 2);
576 	esecs = measure_test("sched_tc5", "-tfixed", pristr, NULL, &esecs2);
577 	display_line("sched_tc5", current_priority, 1, esecs, &e5real, 2);
578 	esecs =
579 	    measure_test("sched_tc6", "-tvariable", pristr, " -d ", &esecs2);
580 	display_line("sched_tc6", current_priority, 0, esecs, &e6user0, 0);
581 	esecs = measure_test("sched_tc6", "-tfixed", pristr, " -d ", &esecs2);
582 	display_line("sched_tc6", current_priority, 1, esecs, &e6real0, 0);
583 	esecs =
584 	    measure_test("sched_tc6", "-tvariable", pristr, " -df ", &esecs2);
585 	display_line("sched_tc6", current_priority, 0, esecs, &e6user1, 1);
586 #endif
587 
588 	/*
589 	 * Manually build the display line for the second part of sched_tc6
590 	 */
591 
592 	/*
593 	 * Calculate the percent change in time
594 	 */
595 	pc = (e6child ==
596 	      0.0) ? 0.0 : 100 * ((esecs2 - e6child) / e6child) + 0.05;
597 	printf("%-12s forked child          %4s   %06.4f  %+06.4f\n",
598 	       "sched_tc6", "real", esecs2, pc);
599 	e6child = esecs2;
600 }
601 
602 /*------------------------ start_long_term_testcases() ------------------*/
603 /* This procedure takes the number of long-term process slots available, *
604  * and executes the long term testcases.				 *
605  *-----------------------------------------------------------------------*/
start_long_term_testcases(long_term_slot_total,execution_time)606 void start_long_term_testcases(long_term_slot_total, execution_time)
607 int long_term_slot_total;	/* total number of long-term slots */
608 char *execution_time;		/* runtime hours to pass to each testcase */
609 {
610 	int i;
611 
612 	/*
613 	 * Now use up the long_term_slot_total by starting testcases call
614 	 * half with real-time flag '1' set, other half user flag '0'
615 	 */
616 	if (debug)
617 		printf("long-term slots available:  %d\n",
618 		       long_term_slot_total);
619 
620 	for (i = 0; i < (long_term_slot_total / 4); i++) {
621 #if defined(_IA64) && !defined(__64BIT__)
622 		start_testcase("./sched_tc0.32", "sched_tc0 -t", execution_time,
623 			       " -p1", NULL, NULL);
624 		start_testcase("./sched_tc2.32", "sched_tc2", execution_time,
625 			       "1", NULL, NULL);
626 		start_testcase("./sched_tc0.32", "sched_tc0 -t", execution_time,
627 			       " -p0", NULL, NULL);
628 		start_testcase("./sched_tc2.32", "sched_tc2", execution_time,
629 			       "0", NULL, NULL);
630 #else
631 		start_testcase("./sched_tc0", "sched_tc0 -t", execution_time,
632 			       " -p1", NULL, NULL);
633 		start_testcase("./sched_tc2", "sched_tc2", execution_time, "1",
634 			       NULL, NULL);
635 		start_testcase("./sched_tc0", "sched_tc0 -t", execution_time,
636 			       " -p0", NULL, NULL);
637 		start_testcase("./sched_tc2", "sched_tc2", execution_time, "0",
638 			       NULL, NULL);
639 #endif
640 	}
641 }
642 
643 /*---------------------------------------------------------------------+
644 |                     start_short_term_testcases ()                    |
645 | ==================================================================== |
646 |                                                                      |
647 | Function:  Starts short term testcases (one for each process slot)   |
648 |                                                                      |
649 +---------------------------------------------------------------------*/
start_short_term_testcases(int short_term_slot_total,double stress_percent,int pri)650 void start_short_term_testcases(int short_term_slot_total,
651 				double stress_percent, int pri)
652 {
653 	int i;
654 	int short_term_slots;	/* number of slots to use */
655 
656 	/*
657 	 * Set up the short_term_slot_total by starting testcases call
658 	 * half with real-time flag '1' set, other half user flag '0'
659 	 */
660 	if (available_user_process_slots() < short_term_slot_total)
661 		short_term_slots =
662 		    available_user_process_slots() * stress_percent / 2;
663 	else
664 		short_term_slots = short_term_slot_total;
665 
666 	printf("\n<< Starting %d short-term testcases>> \n\n",
667 	       short_term_slots);
668 	if (debug)
669 		printf("short-term slots available:  %d\n", short_term_slots);
670 
671 	for (i = 0; i < (short_term_slots / 4); i++) {
672 #if defined(_IA64) && !defined(__64BIT__)
673 		start_testcase("./sched_tc1.32", "sched_tc1", "1", NULL, NULL,
674 			       NULL);
675 		start_testcase("./sched_tc3.32", "sched_tc3", "1", NULL, NULL,
676 			       NULL);
677 		start_testcase("./sched_tc1.32", "sched_tc1", "0", NULL, NULL,
678 			       NULL);
679 		start_testcase("./sched_tc3.32", "sched_tc3", "0", NULL, NULL,
680 			       NULL);
681 #else
682 		start_testcase("./sched_tc1", "sched_tc1", "1", NULL, NULL,
683 			       NULL);
684 		start_testcase("./sched_tc3", "sched_tc3", "1", NULL, NULL,
685 			       NULL);
686 		start_testcase("./sched_tc1", "sched_tc1", "0", NULL, NULL,
687 			       NULL);
688 		start_testcase("./sched_tc3", "sched_tc3", "0", NULL, NULL,
689 			       NULL);
690 #endif
691 #if 0
692 		perform_throughput_tests(pri);
693 #endif
694 	}
695 }
696 
697 /*------------------------ kill_short_term_testcases() ------------------*/
698 /* This procedure goes through the process id table, and sends each	 *
699  * process id number found in the table a signal in order to terminate	 *
700  * it.  The signal sent is SIGUSR1.  It also re-initializes the table.	 *
701  *-----------------------------------------------------------------------*/
kill_short_term_testcases()702 void kill_short_term_testcases()
703 {
704 	int i;			/* loop counter to step through the list of process id's */
705 
706 	/*
707 	 * Loop through the array of process id's one at a time, and
708 	 * attempt to kill each one.  If kill fails, report error and
709 	 * continue.
710 	 */
711 	if (debug)
712 		printf("killing short-term processes...\n");
713 	for (i = 0; i < numprocs; i++) {
714 		if (debug)
715 			printf("killing process [%d]\n", procs[i]);
716 		kill(procs[i], SIGUSR1);
717 	}
718 
719 	/*
720 	 * Adjust the number of short_term_testcases
721 	 */
722 	short_running -= numprocs;
723 
724 	/*
725 	 * Clear the table by setting number of entries to zero
726 	 */
727 	numprocs = 0;
728 }
729 
730 /*----------------------------- finishup() ------------------------------*/
731 /* This procedure closing information to the about ending	 *
732  * times, elapsed times, etc.  This procedure then closes the file*
733  *-----------------------------------------------------------------------*/
finishup(start_time)734 void finishup(start_time)
735 long start_time;		/* starting time to calculate elapsed time */
736 {
737 	long end_time;		/* time when program finished */
738 
739 	/*
740 	 * Get the end time and calculate elapsed time; write all this out
741 	 */
742 	end_time = time(NULL);
743 
744 	printf("\nend time = %s\n", ctime(&end_time));
745 
746 	printf("elapsed time = %4.2f hours\n",
747 	       ((end_time - start_time) / 3600.0));
748 }
749 
750 /*---------------------------------------------------------------------+
751 |                             parse_args ()                            |
752 | ==================================================================== |
753 |                                                                      |
754 | Function:  Parse the command line arguments & initialize global      |
755 |            variables.                                                |
756 |                                                                      |
757 | Updates:   (command line options)                                    |
758 |                                                                      |
759 |            [-s] size: shared memory segment size                     |
760 |                                                                      |
761 +---------------------------------------------------------------------*/
parse_args(int argc,char ** argv)762 void parse_args(int argc, char **argv)
763 {
764 	int opt;
765 	int sflg = 0, pflg = 0, tflg = 0;
766 	int errflag = 0;
767 	char *program_name = *argv;
768 	extern char *optarg;	/* Command line option */
769 
770 	/*
771 	 * Parse command line options.
772 	 */
773 	while ((opt = getopt(argc, argv, "vs:p:t:l:d")) != EOF) {
774 		switch (opt) {
775 		case 's':	/* stress percentage */
776 			sflg++;
777 			stress_percent = atof(optarg);
778 			break;
779 		case 'p':	/* process slots */
780 			pflg++;
781 			process_slots = atof(optarg);
782 			break;
783 		case 't':	/* time (hours) */
784 			tflg++;
785 			execution_time = atof(optarg);
786 			break;
787 		case 'd':	/* Enable debugging messages */
788 			debug++;
789 			break;
790 		case 'v':	/* Enable verbose mode=debug mode */
791 			debug++;
792 			break;
793 		default:
794 			errflag++;
795 			break;
796 		}
797 	}
798 
799 	/*
800 	 * Check percentage, execution time and process slots...
801 	 */
802 	if (sflg) {
803 		if (stress_percent < 0.0 || stress_percent > 1.0)
804 			errflag++;
805 	}
806 	if (pflg) {
807 		if (process_slots < 0 || process_slots > MAXPROCS)
808 			errflag++;
809 	}
810 	if (tflg) {
811 		if (execution_time < 0.0 || execution_time > 100.0)
812 			errflag++;
813 	}
814 	if (debug)
815 		printf("\n(debugging messages enabled)\n\n");
816 	if (errflag) {
817 		fprintf(stderr, USAGE, program_name);
818 		exit(2);
819 	}
820 }
821