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