Home | History | Annotate | Download | only in sched_stress
      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 +---------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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 
    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  *-----------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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  *-----------------------------------------------------------------------*/
    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 +---------------------------------------------------------------------*/
    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