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  * FUNCTIONS: Scheduler Test Suite
     20  */
     21 
     22 /*---------------------------------------------------------------------+
     23 |                               sched_tc6                              |
     24 | ==================================================================== |
     25 |                                                                      |
     26 | Description:  Creates short-term disk I/O bound process              |
     27 |                                                                      |
     28 |		Creates a situation where a real time process is       |
     29 |		waiting on a file lock owned by a user process.  The   |
     30 |		scheduler should elevate the user process priority to  |
     31 |		the same level as the real time process to avoid       |
     32 |		deadlock situations and to decrease wait time          |
     33 |		required of the real time process.                     |
     34 |                                                                      |
     35 | Algorithm:    o  Set process priority                                |
     36 |               o  Continuously multiply matrices together until       |
     37 |                  interrupted.                                        |
     38 |                                                                      |
     39 | To compile:   cc -o sched_tc6 sched_tc6.c -L. -lpsc                  |
     40 |                                                                      |
     41 | Usage:        sched_tc6 [-t priority_type] [-p priority]             |
     42 |                         [-l log] [-f] [-v] [-d]                      |
     43 |                                                                      |
     44 | Last update:   Ver. 1.3, 4/10/94 23:05:03                           |
     45 |                                                                      |
     46 | Change Activity                                                      |
     47 |                                                                      |
     48 |   Version  Date    Name  Reason                                      |
     49 |    0.1     050689  CTU   Initial version                             |
     50 |    0.2     010402  Manoj Iyer Ported to Linux			       |
     51 |                                                                      |
     52 +---------------------------------------------------------------------*/
     53 
     54 #include <fcntl.h>
     55 #include <stdlib.h>
     56 #include <sys/time.h>
     57 #include <time.h>
     58 #include <sys/resource.h>
     59 #include "sched.h"
     60 
     61 /*
     62  * Defines:
     63  *
     64  * USAGE: usage statement
     65  *
     66  * DEFAULT_PRIORITY_TYPE: default priority
     67  *
     68  * BLOCK_SIZE: block size (in bytes) for raw I/O
     69  *
     70  * TIMES: number of times to read raw I/O device (~25MB)
     71  *
     72  */
     73 #define DEFAULT_PRIORITY_TYPE	"variable"
     74 #define DEFAULT_LOGFILE		"sched_tc6.log"
     75 #define BLOCK_SIZE		512
     76 #define TIMES			10
     77 #define MAX_TRIES		20
     78 #define NAPTIME			1
     79 #define REAL_TIME		"1"
     80 #define NO_FORK			"0"
     81 #define USAGE "Usage:  %s  [-l log] [-t type] [-p priority] [-f] [-v] [-d]\n" \
     82               "        -l log      log file                             \n" \
     83               "        -t type     priority type 'variable' or 'fixed'  \n" \
     84               "        -p priority priority value                       \n" \
     85               "        -f          fork child                           \n" \
     86               "        -v          verbose                              \n" \
     87               "        -d          enable debugging messages            \n"
     88 
     89 /*
     90  * Function prototypes:
     91  *
     92  * process_file: reads data file
     93  *
     94  * parse_args: parse command line arguments
     95  */
     96 void parse_args(int, char **);
     97 int fork_realtime(char **);
     98 int read_file(int, char *);
     99 int lock_file(int, short, char *);
    100 int unlock_file(int, char *);
    101 int lock_error(int, char *);
    102 
    103 /*
    104  * Global variables:
    105  *
    106  * verbose: enable normal messages
    107  *
    108  * debug: enable debugging messages
    109  *
    110  * priority: process type (fixed priority, variable priority)
    111  */
    112 int verbose = 0;
    113 int debug = 0;
    114 int fork_flag = 0;
    115 int priority = DEFAULT_PRIORITY;
    116 char *logfile = DEFAULT_LOGFILE;
    117 char *priority_type = DEFAULT_PRIORITY_TYPE;
    118 struct flock flock_struct;
    119 struct flock *flock_ptr = &flock_struct;
    120 
    121 int open_file(char *, int);
    122 
    123 /*---------------------------------------------------------------------+
    124 |                                 main                                 |
    125 | ==================================================================== |
    126 |                                                                      |
    127 | Function:  ...                                                       |
    128 |                                                                      |
    129 +---------------------------------------------------------------------*/
    130 int main(int argc, char **argv)
    131 {
    132 	char *filename = NULL;
    133 	FILE *statfile;
    134 	pid_t pid = 0;
    135 	int fd;
    136 	int rc;
    137 	clock_t start_time;	/* start & stop times */
    138 	clock_t stop_time;
    139 	float elapsed_time;
    140 #ifdef __linux__
    141 	time_t timer_info;
    142 #else
    143 	struct tms timer_info;	/* time accounting info */
    144 #endif
    145 
    146 	if ((filename = getenv("KERNEL")) == NULL) {
    147 		errno = ENODATA;
    148 		sys_error("environment variable KERNEL not set", __FILE__,
    149 			  __LINE__);
    150 	}
    151 
    152 	/* Process command line arguments...  */
    153 	parse_args(argc, argv);
    154 	if (verbose)
    155 		printf("%s: Scheduler TestSuite program\n\n", *argv);
    156 	if (debug) {
    157 		printf("\tpriority type:  %s\n", priority_type);
    158 		printf("\tpriority:       %d\n", priority);
    159 		printf("\tlogfile:        %s\n", logfile);
    160 	}
    161 
    162 	/* Adjust the priority of this process if the real time flag is set */
    163 	if (!strcmp(priority_type, "fixed")) {
    164 #ifndef __linux__
    165 		if (setpri(0, DEFAULT_PRIORITY) < 0)
    166 			sys_error("setpri failed", __FILE__, __LINE__);
    167 #else
    168 		if (setpriority(PRIO_PROCESS, 0, 0) < 0)
    169 			sys_error("setpri failed", __FILE__, __LINE__);
    170 #endif
    171 	} else {
    172 		if (nice((priority - 50) - (nice(0) + 20)) < 0 && errno != 0)
    173 			sys_error("nice failed", __FILE__, __LINE__);
    174 	}
    175 
    176 	/* Read from raw I/O device and record elapsed time...  */
    177 	start_time = time(&timer_info);
    178 
    179 	/* Open and lock file file...  */
    180 	fd = open_file(filename, O_RDWR);
    181 	if (!lock_file(fd, F_WRLCK, filename))	/* set exclusive lock */
    182 		error("lock_file failed", __FILE__, __LINE__);
    183 
    184 	/* If fork flag set, fork a real process */
    185 	if (fork_flag)
    186 		pid = fork_realtime(argv);
    187 
    188 	/* Read file */
    189 	if (debug) {
    190 		printf("\tprocess id %d successfully locked %s\n",
    191 		       getpid(), filename);
    192 		printf("\tprocess id %d starting to read %s\n",
    193 		       getpid(), filename);
    194 	}
    195 
    196 	if (!read_file(fd, filename))
    197 		error("read_file failed", __FILE__, __LINE__);
    198 
    199 	/* Stop the timer and calculate the elapsed time */
    200 	stop_time = time(&timer_info);
    201 	elapsed_time = (float)(stop_time - start_time) / 100.0;
    202 
    203 	/* Write the elapsed time to the temporary file...  */
    204 	if ((statfile = fopen(logfile, "w")) == NULL)
    205 		sys_error("fopen failed", __FILE__, __LINE__);
    206 
    207 	fprintf(statfile, "%f\n", elapsed_time);
    208 	if (debug)
    209 		printf("\n\telapsed time: %f\n", elapsed_time);
    210 
    211 	if (fclose(statfile) < 0)
    212 		sys_error("fclose failed", __FILE__, __LINE__);
    213 
    214 	/* Unlock file at latest possible time to prevent real time child from
    215 	 * writing throughput results before user process parent */
    216 	unlock_file(fd, filename);
    217 	close(fd);
    218 
    219 	if (debug)
    220 		printf("\tprocess id %d completed read and unlocked file\n",
    221 		       getpid());
    222 
    223 	/* The parent waits for child process to complete before exiting
    224 	 * so the driver will not read the throughput results file before
    225 	 * child writes to the file */
    226 	if (pid != 0) {		/* if parent process ... *//* wait for child process */
    227 		if (debug)
    228 			printf
    229 			    ("parent waiting on child process %d to complete\n",
    230 			     pid);
    231 
    232 		while ((rc = wait(NULL)) != pid)
    233 			if (rc == -1)
    234 				sys_error("wait failed", __FILE__, __LINE__);
    235 /*
    236 DARA: which one to use
    237 1st -- hangs
    238 2nd -- ERROR message
    239 
    240 	    while (wait((void *) 0) != pid) ;
    241 	    while ((rc=wait ((void *) 0)) != pid)
    242 	       if (rc == -1)
    243 	          sys_error ("wait failed", __FILE__, __LINE__);
    244 */
    245 	}
    246 
    247 	/* Exit with success! */
    248 	if (verbose)
    249 		printf("\nsuccessful!\n");
    250 	return (0);
    251 }
    252 
    253 /*---------------------------------------------------------------------+
    254 |                             open_file ()                             |
    255 | ==================================================================== |
    256 |                                                                      |
    257 | Function:  ...                                                       |
    258 |                                                                      |
    259 +---------------------------------------------------------------------*/
    260 int open_file(char *file, int open_mode)
    261 {
    262 	int file_desc;
    263 
    264 	if ((file_desc = open(file, open_mode)) < 0)
    265 		sys_error("open failed", __FILE__, __LINE__);
    266 	return (file_desc);
    267 }
    268 
    269 /*---------------------------------------------------------------------+
    270 |                           fork_realtime ()                           |
    271 | ==================================================================== |
    272 |                                                                      |
    273 | Function:  ...                                                       |
    274 |                                                                      |
    275 +---------------------------------------------------------------------*/
    276 int fork_realtime(char **args)
    277 {
    278 	int pid;
    279 	char *results_file = args[2];
    280 	char *priority = args[3];
    281 
    282 	/* fork process then determine if process is parent or child */
    283 	pid = fork();
    284 	switch (pid) {
    285 		/* fork failed  */
    286 	case -1:
    287 		sys_error("fork failed", __FILE__, __LINE__);
    288 
    289 		/* child process */
    290 	case 0:
    291 		if (execl(*args, *args, REAL_TIME, results_file, priority,
    292 			  NO_FORK, NULL) < 0)
    293 			sys_error("execl failed", __FILE__, __LINE__);
    294 
    295 		/* parent process */
    296 	default:
    297 #ifdef DEBUG
    298 		printf("\tparent process id = %d\n", getpid());
    299 		printf("\tchild process id = %d\n\n", pid);
    300 #endif
    301 
    302 		break;
    303 	}
    304 	return (pid);
    305 }
    306 
    307 /*---------------------------------------------------------------------+
    308 |                             read_file ()                             |
    309 | ==================================================================== |
    310 |                                                                      |
    311 | Function:  ...                                                       |
    312 |                                                                      |
    313 +---------------------------------------------------------------------*/
    314 int read_file(int fd, char *filename)
    315 {
    316 	int bytes_read;
    317 	int loop_count;
    318 	long total_bytes;
    319 	off_t lseek();
    320 	off_t file_offset = 0;
    321 	int whence = 0;
    322 
    323 	char buf[BLOCK_SIZE];
    324 
    325 	/* read file for "TIMES" number of times */
    326 	total_bytes = 0;
    327 	if (debug)
    328 		printf("\n");
    329 	for (loop_count = 1; loop_count <= TIMES; loop_count++) {
    330 		while ((bytes_read = read(fd, buf, BLOCK_SIZE)) > 0) {
    331 			if (bytes_read == -1) {
    332 				sys_error("read failed", __FILE__, __LINE__);
    333 			} else
    334 				total_bytes = total_bytes + bytes_read;
    335 		}
    336 		if (lseek(fd, file_offset, whence) < 0)
    337 			sys_error("lseek failed", __FILE__, __LINE__);
    338 
    339 		if (debug) {
    340 			printf("\r\ttotal bytes read = %ld", total_bytes);
    341 			fflush(stdout);
    342 		}
    343 		total_bytes = 0;
    344 	}
    345 	if (debug)
    346 		printf("\n");
    347 	return 1;
    348 }
    349 
    350 /*---------------------------------------------------------------------+
    351 |                             lock_file ()                             |
    352 | ==================================================================== |
    353 |                                                                      |
    354 | Function:  ...                                                       |
    355 |                                                                      |
    356 +---------------------------------------------------------------------*/
    357 int lock_file(int fd, short lock_type, char *file)
    358 {
    359 	int lock_attempt = 1;
    360 	int lock_mode;
    361 
    362 #ifdef DEBUG
    363 	lock_mode = F_SETLK;	/* return if lock fails        */
    364 #else
    365 	lock_mode = F_SETLKW;	/* set lock and use system wait */
    366 #endif
    367 
    368 	/* file segment locking set data type flock - information
    369 	 * passed to system by user --
    370 	 *   l_whence:  starting point of relative offset of file
    371 	 *   l_start:   defines relative offset in bytes from l_whence
    372 	 *   l_len:     number of consecutive bytes to be locked
    373 	 */
    374 	flock_ptr->l_whence = 0;
    375 	flock_ptr->l_start = 0;
    376 	flock_ptr->l_len = 0;
    377 	flock_ptr->l_type = lock_type;
    378 
    379 	while (fcntl(fd, lock_mode, flock_ptr) == -1) {
    380 		if (lock_error(fd, file)) {
    381 			sleep(NAPTIME);
    382 			if (++lock_attempt > MAX_TRIES) {
    383 				printf
    384 				    ("ERROR: max lock attempts of %d reached\n",
    385 				     MAX_TRIES);
    386 				return (0);
    387 			}
    388 		} else
    389 			return (0);
    390 	}
    391 	return (1);
    392 }
    393 
    394 /*---------------------------------------------------------------------+
    395 |                            unlock_file ()                            |
    396 | ==================================================================== |
    397 |                                                                      |
    398 | Function:  ...                                                       |
    399 |                                                                      |
    400 +---------------------------------------------------------------------*/
    401 int unlock_file(int fd, char *file)
    402 {
    403 	flock_ptr->l_type = F_UNLCK;
    404 
    405 	if (fcntl(fd, F_SETLK, flock_ptr) < 0)
    406 		sys_error("fcntl failed", __FILE__, __LINE__);
    407 
    408 	return 1;
    409 }
    410 
    411 /*---------------------------------------------------------------------+
    412 |                                 main                                 |
    413 | ==================================================================== |
    414 |                                                                      |
    415 | Function:  ...                                                       |
    416 |                                                                      |
    417 +---------------------------------------------------------------------*/
    418 int lock_error(int fd, char *file)
    419 {
    420 	int ret = 1;
    421 
    422 	printf("ERROR:  lock failed: %s\n", file);
    423 	switch (errno) {
    424 	case EACCES:		/* access not allowed */
    425 		fcntl(fd, F_GETLK, flock_ptr);
    426 #ifndef __linux__
    427 		printf("ERROR: lock exists - nid: %lX pid: %ld\n",
    428 		       flock_ptr->l_sysid, flock_ptr->l_pid);
    429 #else
    430 		printf("ERROR: lock exists - nid:\n");
    431 #endif
    432 		break;
    433 
    434 		/*
    435 		 * This was a DS error code, and DS does not exist V3.1
    436 		 */
    437 #ifndef __linux__
    438 	case EDIST:		/* DS file server blocking requests */
    439 		printf("ERROR: errno == EDIST\n");
    440 		printf("The server has blocked new inbound requests\n");
    441 		printf("or outbound requests are currently blocked.\n");
    442 		break;
    443 #endif
    444 
    445 	case EAGAIN:		/* server too busy */
    446 		printf("ERROR:  Server too busy to accept the request\n");
    447 		break;
    448 
    449 	case EDEADLK:		/* only when F_SETLKW cmd is used */
    450 		printf("ERROR:  Putting the calling process to sleep\n");
    451 		printf("would cause a dead lock\n");
    452 		ret = 0;
    453 		break;
    454 
    455 	case ENOLCK:		/* out of locks */
    456 		printf("ERROR: No more file locks available\n");
    457 		ret = 0;
    458 		break;
    459 
    460 	case ENOMEM:		/* out of memory */
    461 		printf("ERROR: The server or client does not have enough\n");
    462 		printf("memory to service the request.\n");
    463 		ret = 0;
    464 		break;
    465 
    466 	default:		/* miscellaneous errors */
    467 		printf("ERROR: Unknown lock error\n");
    468 		perror("reason");
    469 		ret = 0;
    470 		break;
    471 	}
    472 
    473 	printf("errno = %d\n", errno);	/* log the errno value */
    474 	sleep(10);
    475 
    476 	return (ret);
    477 }
    478 
    479 /*---------------------------------------------------------------------+
    480 |                             parse_args ()                            |
    481 | ==================================================================== |
    482 |                                                                      |
    483 | Function:  Parse the command line arguments & initialize global      |
    484 |            variables.                                                |
    485 |                                                                      |
    486 | Updates:   (command line options)                                    |
    487 |                                                                      |
    488 |            [-t] type:     priority type "fixed" or "variable"        |
    489 |            [-p] priority: priority value                             |
    490 |            [-l] logfile:  log file name                              |
    491 |            [-v]           verbose                                    |
    492 |            [-d]           enable debugging messages                  |
    493 |                                                                      |
    494 +---------------------------------------------------------------------*/
    495 void parse_args(int argc, char **argv)
    496 {
    497 	int opt;
    498 	int lflg = 0, pflg = 0, tflg = 0;
    499 	int errflag = 0;
    500 	char *program_name = *argv;
    501 	extern char *optarg;	/* Command line option */
    502 
    503 	/*
    504 	 * Parse command line options.
    505 	 */
    506 	while ((opt = getopt(argc, argv, "fl:t:p:vd")) != EOF) {
    507 		switch (opt) {
    508 		case 'f':	/* fork flag */
    509 			fork_flag++;
    510 			break;
    511 		case 'l':	/* log file */
    512 			lflg++;
    513 			logfile = optarg;
    514 			break;
    515 		case 't':	/* process type */
    516 			tflg++;
    517 			priority_type = optarg;
    518 			break;
    519 		case 'p':	/* process priority */
    520 			pflg++;
    521 			priority = atoi(optarg);
    522 			break;
    523 		case 'v':	/* verbose */
    524 			verbose++;
    525 			break;
    526 		case 'd':	/* enable debugging messages */
    527 			verbose++;
    528 			debug++;
    529 			break;
    530 		default:
    531 			errflag++;
    532 			break;
    533 		}
    534 	}
    535 
    536 	/*
    537 	 * Check percentage and process slots...
    538 	 */
    539 	if (tflg) {
    540 		if (strcmp(priority_type, "fixed") &&
    541 		    strcmp(priority_type, "variable")) {
    542 			errflag++;
    543 			fprintf(stderr, "Error: priority type must be: "
    544 				"\'fixed\' or \'variable\'\n");
    545 		}
    546 	}
    547 	if (pflg) {
    548 		if (priority < 50 || priority > 100) {
    549 			errflag++;
    550 			fprintf(stderr, "Error: priority range [50..100]\n");
    551 		}
    552 	}
    553 	if (errflag) {
    554 		fprintf(stderr, USAGE, program_name);
    555 		exit(2);
    556 	}
    557 }
    558