Home | History | Annotate | Download | only in disktest
      1 /*
      2 * $Id: timer.c,v 1.6 2009/02/26 12:02:23 subrata_modak Exp $
      3 * Disktest
      4 * Copyright (c) International Business Machines Corp., 2001
      5 *
      6 *
      7 * This program is free software; you can redistribute it and/or modify
      8 * it under the terms of the GNU General Public License as published by
      9 * the Free Software Foundation; either version 2 of the License, or
     10 * (at your option) any later version.
     11 *
     12 * This program is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 * GNU General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU General Public License
     18 * along with this program; if not, write to the Free Software
     19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     20 *
     21 *  Please send e-mail to yardleyb (at) us.ibm.com if you have
     22 *  questions or comments.
     23 *
     24 *  Project Website:  TBD
     25 *
     26 * $Id: timer.c,v 1.6 2009/02/26 12:02:23 subrata_modak Exp $
     27 *
     28 */
     29 #include <stdio.h>
     30 #ifdef WINDOWS
     31 #include <windows.h>
     32 #include <winioctl.h>
     33 #include <io.h>
     34 #include <process.h>
     35 #include <sys/stat.h>
     36 #include "getopt.h"
     37 #else
     38 #include <sys/types.h>
     39 #include <sys/time.h>
     40 #include <unistd.h>
     41 #endif
     42 #include <stdlib.h>
     43 #include <stdarg.h>
     44 #include <stdint.h>
     45 #include <signal.h>
     46 #include <time.h>
     47 #include <errno.h>
     48 #include <fcntl.h>
     49 #include <string.h>
     50 #include <ctype.h>
     51 
     52 #include "defs.h"
     53 #include "globals.h"
     54 #include "threading.h"
     55 #include "sfunc.h"
     56 #include "stats.h"
     57 #include "signals.h"
     58 
     59 /*
     60  * The main purpose of this thread is track time during the test. Along with
     61  * keeping track of read/write time. And check that each interval, that the
     62  * IO threads are making progress. The timer thread is started before any IO
     63  * threads and will complete either after all IO threads exit, the test fails,
     64  * or if a timed run, the run time is exceeded.
     65  */
     66 #ifdef WINDOWS
     67 DWORD WINAPI ChildTimer(test_ll_t * test)
     68 #else
     69 void *ChildTimer(void *vtest)
     70 #endif
     71 {
     72 #ifndef WINDOWS
     73 	test_ll_t *test = (test_ll_t *) vtest;
     74 #endif
     75 	time_t ioTimeoutCount = 0;
     76 	time_t total_time = 0;
     77 	OFF_T cur_total_io_count = 0;
     78 	OFF_T last_total_io_count = 0;
     79 
     80 	OFF_T tmp_io_count = 0;
     81 	time_t run_time = 0;
     82 
     83 	lvl_t msg_level = WARN;
     84 
     85 	child_args_t *args = test->args;
     86 	test_env_t *env = test->env;
     87 
     88 	extern int signal_action;
     89 	extern unsigned short glb_run;
     90 
     91 #ifdef _DEBUG
     92 	PDBG3(DBUG, args, "In timer %lu, %d\n", time(NULL), env->bContinue);
     93 #endif
     94 	do {
     95 		Sleep(1000);
     96 		run_time++;
     97 #ifdef _DEBUG
     98 		PDBG3(DBUG, args, "Continue timing %lu, %lu, %d\n", time(NULL),
     99 		      run_time, env->bContinue);
    100 #endif
    101 		if (args->flags & CLD_FLG_W) {
    102 			if ((args->flags & CLD_FLG_LINEAR)
    103 			    && !(args->flags & CLD_FLG_NTRLVD)) {
    104 				if (TST_OPER(args->test_state) == WRITER) {
    105 					env->hbeat_stats.wtime++;
    106 				}
    107 			} else {
    108 				env->hbeat_stats.wtime++;
    109 			}
    110 		}
    111 		if (args->flags & CLD_FLG_R) {
    112 			if ((args->flags & CLD_FLG_LINEAR)
    113 			    && !(args->flags & CLD_FLG_NTRLVD)) {
    114 				if (TST_OPER(args->test_state) == READER) {
    115 					env->hbeat_stats.rtime++;
    116 				}
    117 			} else {
    118 				env->hbeat_stats.rtime++;
    119 			}
    120 		}
    121 
    122 		/*
    123 		 * Check to see if we have made any IO progress in the last interval,
    124 		 * if not incremment the ioTimeout timer, otherwise, clear it
    125 		 */
    126 		cur_total_io_count = env->global_stats.wcount
    127 		    + env->cycle_stats.wcount
    128 		    + env->hbeat_stats.wcount
    129 		    + env->global_stats.rcount
    130 		    + env->cycle_stats.rcount + env->hbeat_stats.rcount;
    131 
    132 		if (cur_total_io_count == 0) {
    133 			tmp_io_count = 1;
    134 		} else {
    135 			tmp_io_count = cur_total_io_count;
    136 		}
    137 
    138 		total_time = env->global_stats.rtime
    139 		    + env->cycle_stats.rtime
    140 		    + env->hbeat_stats.rtime
    141 		    + env->global_stats.wtime
    142 		    + env->cycle_stats.wtime + env->hbeat_stats.wtime;
    143 
    144 #ifdef _DEBUG
    145 		PDBG3(DBUG, args, "average number of seconds per IO: %0.8lf\n",
    146 		      ((double)(total_time) / (double)(tmp_io_count)));
    147 #endif
    148 
    149 		if (cur_total_io_count == last_total_io_count) {	/* no IOs completed in interval */
    150 			if (0 == (++ioTimeoutCount % args->ioTimeout)) {	/* no progress after modulo ioTimeout interval */
    151 				if (args->flags & CLD_FLG_TMO_ERROR) {
    152 					args->test_state =
    153 					    SET_STS_FAIL(args->test_state);
    154 					env->bContinue = FALSE;
    155 					msg_level = ERR;
    156 				}
    157 				pMsg(msg_level, args,
    158 				     "Possible IO hang condition, IO timeout reached, %lu seconds\n",
    159 				     args->ioTimeout);
    160 			}
    161 #ifdef _DEBUG
    162 			PDBG3(DBUG, args, "io timeout count: %lu\n",
    163 			      ioTimeoutCount);
    164 #endif
    165 		} else {
    166 			ioTimeoutCount = 0;
    167 			last_total_io_count = cur_total_io_count;
    168 #ifdef _DEBUG
    169 			PDBG3(DBUG, args, "io timeout reset\n");
    170 #endif
    171 		}
    172 
    173 		if (((args->hbeat > 0) && ((run_time % args->hbeat) == 0))
    174 		    || (signal_action & SIGNAL_STAT)) {
    175 			print_stats(args, env, HBEAT);
    176 			update_cyc_stats(env);
    177 			clear_stat_signal();
    178 		}
    179 
    180 		if (glb_run == 0) {
    181 			break;
    182 		}		/* global run flag cleared */
    183 		if (signal_action & SIGNAL_STOP) {
    184 			break;
    185 		}
    186 		/* user request to stop */
    187 		if (args->flags & CLD_FLG_TMD) {	/* if timing */
    188 			if (run_time >= args->run_time) {	/* and run time exceeded */
    189 				break;
    190 			}
    191 		} else {	/* if not timing */
    192 			if (env->kids <= 1) {	/* and the timer is the only child */
    193 				break;
    194 			}
    195 		}
    196 	} while (TRUE);
    197 #ifdef _DEBUG
    198 	PDBG3(DBUG, args, "Out of timer %lu, %lu, %d, %d\n", time(NULL),
    199 	      run_time, env->bContinue, env->kids);
    200 #endif
    201 
    202 	if (args->flags & CLD_FLG_TMD) {	/* timed test, timer exit needs to stop io threads */
    203 #ifdef _DEBUG
    204 		PDBG3(DBUG, args,
    205 		      "Setting bContinue to FALSE, timed test & timer exit\n");
    206 #endif
    207 		env->bContinue = FALSE;
    208 	}
    209 
    210 	TEXIT((uintptr_t) GETLASTERROR());
    211 }
    212 
    213 #ifdef _DEBUG
    214 #ifdef WINDOWS
    215 DWORD startTime;
    216 DWORD endTime;
    217 
    218 void setStartTime(void)
    219 {
    220 	startTime = GetTickCount();
    221 }
    222 
    223 void setEndTime(void)
    224 {
    225 	endTime = GetTickCount();
    226 }
    227 
    228 unsigned long getTimeDiff(void)
    229 {
    230 	return ((endTime - startTime) * 1000);	/* since we report in usecs, and windows is msec, multiply by 1000 */
    231 }
    232 #else
    233 struct timeval tv_start;
    234 struct timeval tv_end;
    235 
    236 void setStartTime(void)
    237 {
    238 	gettimeofday(&tv_start, NULL);
    239 }
    240 
    241 void setEndTime(void)
    242 {
    243 	gettimeofday(&tv_end, NULL);
    244 }
    245 
    246 unsigned long getTimeDiff(void)
    247 {
    248 	return (tv_end.tv_usec - tv_start.tv_usec);
    249 }
    250 
    251 #endif
    252 #endif
    253