Freeciv-3.1: /fast/freeciv/nightly/S3_1/utility/timing.c Source File

Freeciv-3.1

Loading...
Searching...
No Matches
timing.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14/**********************************************************************
15 Measuring times; original author: David Pfitzner <dwp@mso.anu.edu.au>
16
17 We assume we have at least ANSI/ISO C timing functions, so
18 that we can use:
19 clock_t clock() for CPU times
20 time_t time() for user-time
21 If we have HAVE_GETTIMEOFDAY we use gettimeofday() for user-time
22 to get (usually) better resolution than time().
23
24 As well as measuring single time intervals, these functions
25 support accumulating the time from multiple separate intervals.
26
27 Notice the struct timer is an opaque type: modules outside timing.c
28 can only use it as a pointer (cf FILE type). This is done for two
29 main reasons:
30
31 1. General principle of data hiding and encapsulation
32
33 2. Means we don't have to include fc_config.h and possibly system
34 specific header files in timing.h. Such stuff is confined
35 inside timing.c.
36
37 However there is a disadvantage: any code using a timer must do
38 memory allocation and deallocation for it. Some of the functions
39 below are intended to make this reasonably convenient; see function
40 comments.
41***********************************************************************/
42
43#ifdef HAVE_CONFIG_H
44#include <fc_config.h>
45#endif
46
47#include <time.h>
48
49#ifdef HAVE_GETTIMEOFDAY
50#include <sys/time.h>
51#include <unistd.h>
52#endif
53
54#ifdef HAVE_FTIME
55# include <sys/timeb.h>
56#endif
57
58/* utility */
59#include "log.h"
60#include "mem.h"
61#include "shared.h" /* TRUE, FALSE */
62#include "support.h"
63
64#include "timing.h"
65
66#ifndef CLOCKS_PER_SEC
67#ifdef CLOCKS_PER_SECOND
68#define CLOCKS_PER_SEC CLOCKS_PER_SECOND
69#else
70#define CLOCKS_PER_SEC 1000000 /* wild guess!! */
71#endif
72#endif
73
74#define N_USEC_PER_SEC 1000000L /* not 1000! :-) */
75
76 enum timer_state {
77 TIMER_STARTED,
78 TIMER_STOPPED
79};
80
81 struct timer {
82 /* type: */
83 enum timer_timetype type;
84 enum timer_use use;
85 enum timer_state state;
86
87 /* this is accumulated time for previous timings: */
88 double sec;
89 long usec; /* not always used, in which case zero,
90 or if used may be negative, but >= -1000000 */
91
92 /* this is start of current timing, if state == TIMER_STARTED: */
93 union {
94 clock_t c;
95#ifdef HAVE_GETTIMEOFDAY
96 struct timeval tv;
97#elif HAVE_FTIME
98 struct timeb tp;
99#else
100 time_t t;
101#endif
102 } start;
103};
104
105/*******************************************************************/
109 static void report_clock_failed(struct timer *t)
110{
111 static bool first = TRUE;
112
113 if (first) {
114 log_test("clock() returned -1, ignoring timer");
115 first = FALSE;
116 }
117 t->use = TIMER_IGNORE;
118}
119
120#ifdef HAVE_GETTIMEOFDAY
121/*******************************************************************/
125static void report_gettimeofday_failed(struct timer *t)
126{
127 static bool first = TRUE;
128
129 if (first) {
130 log_test("gettimeofday() returned -1, ignoring timer");
131 first = FALSE;
132 }
133 t->use = TIMER_IGNORE;
134}
135#elif !defined HAVE_FTIME
136/*******************************************************************/
140 static void report_time_failed(struct timer *t)
141{
142 static bool first = TRUE;
143
144 if (first) {
145 log_test("time() returned -1, ignoring timer");
146 first = FALSE;
147 }
148 t->use = TIMER_IGNORE;
149}
150#endif
151
152
153/*******************************************************************/
157 struct timer *timer_new(enum timer_timetype type, enum timer_use use)
158{
159 return timer_renew(NULL, type, use);
160}
161
162/*******************************************************************/
176 struct timer *timer_renew(struct timer *t, enum timer_timetype type,
177 enum timer_use use)
178{
179 if (!t) {
180 t = (struct timer *)fc_malloc(sizeof(struct timer));
181 }
182 t->type = type;
183 t->use = use;
184 timer_clear(t);
185 return t;
186}
187
188/*******************************************************************/
191 void timer_destroy(struct timer *t)
192{
193 if (t != NULL) {
194 free(t);
195 }
196}
197
198/*******************************************************************/
202 bool timer_in_use(struct timer *t)
203{
204 return (t && t->use != TIMER_IGNORE);
205}
206
207/*******************************************************************/
212 void timer_clear(struct timer *t)
213{
214 fc_assert_ret(NULL != t);
215 t->state = TIMER_STOPPED;
216 t->sec = 0.0;
217 t->usec = 0;
218}
219
220/*******************************************************************/
224 void timer_start(struct timer *t)
225{
226 fc_assert_ret(NULL != t);
227
228 if (t->use == TIMER_IGNORE) {
229 return;
230 }
231 if (t->state == TIMER_STARTED) {
232 log_error("tried to start already started timer");
233 return;
234 }
235 if (t->type == TIMER_CPU) {
236 t->start.c = clock();
237 if (t->start.c == (clock_t) -1) {
238 report_clock_failed(t);
239 return;
240 }
241 } else {
242#ifdef HAVE_GETTIMEOFDAY
243 int ret = gettimeofday(&t->start.tv, NULL);
244
245 if (ret == -1) {
246 report_gettimeofday_failed(t);
247 return;
248 }
249#elif defined HAVE_FTIME
250 ftime(&t->start.tp);
251#else
252 t->start.t = time(NULL);
253 if (t->start.t == (time_t) -1) {
254 report_time_failed(t);
255 return;
256 }
257#endif
258 }
259 t->state = TIMER_STARTED;
260}
261
262/*******************************************************************/
268 void timer_stop(struct timer *t)
269{
270 fc_assert_ret(NULL != t);
271
272 if (t->use == TIMER_IGNORE) {
273 return;
274 }
275 if (t->state == TIMER_STOPPED) {
276 log_error("tried to stop already stopped timer");
277 return;
278 }
279 if (t->type == TIMER_CPU) {
280 clock_t now = clock();
281
282 if (now == (clock_t) -1) {
283 report_clock_failed(t);
284 return;
285 }
286 t->sec += (now - t->start.c) / (double)CLOCKS_PER_SEC;
287 t->start.c = now;
288 } else {
289#ifdef HAVE_GETTIMEOFDAY
290 struct timeval now;
291 int ret = gettimeofday(&now, NULL);
292
293 if (ret == -1) {
294 report_gettimeofday_failed(t);
295 return;
296 }
297 t->usec += (now.tv_usec - t->start.tv.tv_usec);
298 t->sec += (now.tv_sec - t->start.tv.tv_sec);
299 if (t->usec < 0) {
300 t->usec += N_USEC_PER_SEC;
301 t->sec -= 1.0;
302 } else if (t->usec >= N_USEC_PER_SEC) {
303 long sec = t->usec / N_USEC_PER_SEC;
304
305 t->sec += sec;
306 t->usec -= sec * N_USEC_PER_SEC;
307 }
308 t->start.tv = now;
309#elif defined HAVE_FTIME
310 struct timeb now;
311
312 ftime(&now);
313 t->usec += 1000 * ((long)now.millitm - (long)t->start.tp.millitm);
314 t->sec += now.time - t->start.tp.time;
315 if (t->usec < 0) {
316 t->usec += N_USEC_PER_SEC;
317 t->sec -= 1.0;
318 } else if (t->usec >= N_USEC_PER_SEC) {
319 long sec = t->usec / N_USEC_PER_SEC;
320
321 t->sec += sec;
322 t->usec -= sec * N_USEC_PER_SEC;
323 }
324 t->start.tp = now;
325#else
326 time_t now = time(NULL);
327
328 if (now == (time_t) -1) {
329 report_time_failed(t);
330 return;
331 }
332 t->sec += difftime(now, t->start.t);
333 t->start.t = now;
334#endif
335 }
336 t->state = TIMER_STOPPED;
337}
338
339/*******************************************************************/
344 double timer_read_seconds(struct timer *t)
345{
346 fc_assert_ret_val(NULL != t, -1.0);
347
348 if (t->use == TIMER_IGNORE) {
349 return 0.0;
350 }
351 if (t->state == TIMER_STARTED) {
352 timer_stop(t);
353 t->state = TIMER_STARTED;
354 }
355 return t->sec + t->usec / (double)N_USEC_PER_SEC;
356}
357
358/*******************************************************************/
364 void timer_usleep_since_start(struct timer *t, long usec)
365{
366#ifdef HAVE_GETTIMEOFDAY
367 int ret;
368 struct timeval tv_now;
369 long elapsed_usec;
370 long wait_usec;
371
372 fc_assert_ret(NULL != t);
373
374 ret = gettimeofday(&tv_now, NULL);
375
376 if ((ret == -1)
377 || (t->type != TIMER_USER)
378 || (t->use != TIMER_ACTIVE)
379 || (t->state != TIMER_STARTED)) {
380 fc_usleep(usec);
381 return;
382 }
383
384 elapsed_usec =
385 (tv_now.tv_sec - t->start.tv.tv_sec) * N_USEC_PER_SEC +
386 (tv_now.tv_usec - t->start.tv.tv_usec);
387 wait_usec = usec - elapsed_usec;
388
389 if (wait_usec > 0)
390 fc_usleep(wait_usec);
391#elif HAVE_FTIME
392 struct timeb now;
393 long elapsed_usec, wait_usec;
394
395 ftime(&now);
396
397 elapsed_usec = (now.time - t->start.tp.time) * N_USEC_PER_SEC
398 + (now.millitm - t->start.tp.millitm);
399 wait_usec = usec - elapsed_usec;
400
401 if (wait_usec > 0) {
402 fc_usleep(wait_usec);
403 }
404#else
405 fc_usleep(usec);
406#endif
407}
type
GType type
Definition repodlgs.c:1312
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_test
#define log_test
Definition log.h:136
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
log_error
#define log_error(message,...)
Definition log.h:103
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
shared.h
timer
Definition timing.c:81
timer::type
enum timer_timetype type
Definition timing.c:83
timer::t
time_t t
Definition timing.c:100
timer::sec
double sec
Definition timing.c:88
timer::usec
long usec
Definition timing.c:89
timer::use
enum timer_use use
Definition timing.c:84
timer::c
clock_t c
Definition timing.c:94
timer::state
enum timer_state state
Definition timing.c:85
timer::start
union timer::@11 start
fc_usleep
void fc_usleep(unsigned long usec)
Definition support.c:640
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
timer_new
struct timer * timer_new(enum timer_timetype type, enum timer_use use)
Definition timing.c:157
CLOCKS_PER_SEC
#define CLOCKS_PER_SEC
Definition timing.c:70
report_time_failed
static void report_time_failed(struct timer *t)
Definition timing.c:140
timer_usleep_since_start
void timer_usleep_since_start(struct timer *t, long usec)
Definition timing.c:364
report_clock_failed
static void report_clock_failed(struct timer *t)
Definition timing.c:109
timer_clear
void timer_clear(struct timer *t)
Definition timing.c:212
timer_in_use
bool timer_in_use(struct timer *t)
Definition timing.c:202
N_USEC_PER_SEC
#define N_USEC_PER_SEC
Definition timing.c:74
timer_destroy
void timer_destroy(struct timer *t)
Definition timing.c:191
timer_start
void timer_start(struct timer *t)
Definition timing.c:224
timer_stop
void timer_stop(struct timer *t)
Definition timing.c:268
timer_state
timer_state
Definition timing.c:76
TIMER_STARTED
@ TIMER_STARTED
Definition timing.c:77
TIMER_STOPPED
@ TIMER_STOPPED
Definition timing.c:78
timer_read_seconds
double timer_read_seconds(struct timer *t)
Definition timing.c:344
timer_renew
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use)
Definition timing.c:176
timing.h
timer_use
timer_use
Definition timing.h:44
TIMER_ACTIVE
@ TIMER_ACTIVE
Definition timing.h:45
TIMER_IGNORE
@ TIMER_IGNORE
Definition timing.h:46
timer_timetype
timer_timetype
Definition timing.h:39
TIMER_CPU
@ TIMER_CPU
Definition timing.h:40
TIMER_USER
@ TIMER_USER
Definition timing.h:41