• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
ChildTimer(test_ll_t * test)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 
setStartTime(void)218 void setStartTime(void)
219 {
220 	startTime = GetTickCount();
221 }
222 
setEndTime(void)223 void setEndTime(void)
224 {
225 	endTime = GetTickCount();
226 }
227 
getTimeDiff(void)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 
setStartTime(void)236 void setStartTime(void)
237 {
238 	gettimeofday(&tv_start, NULL);
239 }
240 
setEndTime(void)241 void setEndTime(void)
242 {
243 	gettimeofday(&tv_end, NULL);
244 }
245 
getTimeDiff(void)246 unsigned long getTimeDiff(void)
247 {
248 	return (tv_end.tv_usec - tv_start.tv_usec);
249 }
250 
251 #endif
252 #endif
253