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
67DWORD WINAPI ChildTimer(test_ll_t * test)
68#else
69void *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
215DWORD startTime;
216DWORD endTime;
217
218void setStartTime(void)
219{
220	startTime = GetTickCount();
221}
222
223void setEndTime(void)
224{
225	endTime = GetTickCount();
226}
227
228unsigned long getTimeDiff(void)
229{
230	return ((endTime - startTime) * 1000);	/* since we report in usecs, and windows is msec, multiply by 1000 */
231}
232#else
233struct timeval tv_start;
234struct timeval tv_end;
235
236void setStartTime(void)
237{
238	gettimeofday(&tv_start, NULL);
239}
240
241void setEndTime(void)
242{
243	gettimeofday(&tv_end, NULL);
244}
245
246unsigned long getTimeDiff(void)
247{
248	return (tv_end.tv_usec - tv_start.tv_usec);
249}
250
251#endif
252#endif
253