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
80
81struct timer {
82 /* type: */
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
103};
104
105/*******************************************************************/
109static 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/*******************************************************************/
140static 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/*******************************************************************/
158{
159 return timer_renew(NULL, type, use);
160}
161
162/*******************************************************************/
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/*******************************************************************/
191void timer_destroy(struct timer *t)
192{
193 if (t != NULL) {
194 free(t);
195 }
196}
197
198/*******************************************************************/
202bool timer_in_use(struct timer *t)
203{
204 return (t && t->use != TIMER_IGNORE);
205}
206
207/*******************************************************************/
212void 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/*******************************************************************/
224void 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) {
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) {
255 return;
256 }
257#endif
258 }
259 t->state = TIMER_STARTED;
260}
261
262/*******************************************************************/
268void 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) {
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) {
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/*******************************************************************/
344double 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/*******************************************************************/
364void 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}
GType type
Definition repodlgs.c:1312
#define fc_assert_ret(condition)
Definition log.h:191
#define log_test
Definition log.h:136
#define fc_assert_ret_val(condition, val)
Definition log.h:194
#define log_error(message,...)
Definition log.h:103
#define fc_malloc(sz)
Definition mem.h:34
Definition timing.c:81
enum timer_timetype type
Definition timing.c:83
time_t t
Definition timing.c:100
double sec
Definition timing.c:88
long usec
Definition timing.c:89
enum timer_use use
Definition timing.c:84
clock_t c
Definition timing.c:94
enum timer_state state
Definition timing.c:85
union timer::@11 start
void fc_usleep(unsigned long usec)
Definition support.c:640
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
struct timer * timer_new(enum timer_timetype type, enum timer_use use)
Definition timing.c:157
#define CLOCKS_PER_SEC
Definition timing.c:70
static void report_time_failed(struct timer *t)
Definition timing.c:140
void timer_usleep_since_start(struct timer *t, long usec)
Definition timing.c:364
static void report_clock_failed(struct timer *t)
Definition timing.c:109
void timer_clear(struct timer *t)
Definition timing.c:212
bool timer_in_use(struct timer *t)
Definition timing.c:202
#define N_USEC_PER_SEC
Definition timing.c:74
void timer_destroy(struct timer *t)
Definition timing.c:191
void timer_start(struct timer *t)
Definition timing.c:224
void timer_stop(struct timer *t)
Definition timing.c:268
timer_state
Definition timing.c:76
@ TIMER_STARTED
Definition timing.c:77
@ TIMER_STOPPED
Definition timing.c:78
double timer_read_seconds(struct timer *t)
Definition timing.c:344
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use)
Definition timing.c:176
timer_use
Definition timing.h:44
@ TIMER_ACTIVE
Definition timing.h:45
@ TIMER_IGNORE
Definition timing.h:46
timer_timetype
Definition timing.h:39
@ TIMER_CPU
Definition timing.h:40
@ TIMER_USER
Definition timing.h:41