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