Freeciv-3.2: /fast/freeciv/nightly/S3_2/utility/timing.c Source File

Freeciv-3.2

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#ifdef FREECIV_DEBUG
88 char *name;
89#endif
90
91 /* This is accumulated time for previous timings: */
92 double sec;
93 long usec; /* Not always used, in which case zero,
94 or if used may be negative, but >= -1000000 */
95
96 /* This is start of current timing, if state == TIMER_STARTED: */
97 union {
98 clock_t c;
99#ifdef HAVE_GETTIMEOFDAY
100 struct timeval tv;
101#elif HAVE_FTIME
102 struct timeb tp;
103#else
104 time_t t;
105#endif
106 } start;
107};
108
109/*******************************************************************/
113 static void report_clock_failed(struct timer *t)
114{
115 static bool first = TRUE;
116
117 if (first) {
118 log_test("clock() returned -1, ignoring timer");
119 first = FALSE;
120 }
121 t->use = TIMER_IGNORE;
122}
123
124#ifdef HAVE_GETTIMEOFDAY
125/*******************************************************************/
129static void report_gettimeofday_failed(struct timer *t)
130{
131 static bool first = TRUE;
132
133 if (first) {
134 log_test("gettimeofday() returned -1, ignoring timer");
135 first = FALSE;
136 }
137 t->use = TIMER_IGNORE;
138}
139#elif !defined HAVE_FTIME
140/*******************************************************************/
144 static void report_time_failed(struct timer *t)
145{
146 static bool first = TRUE;
147
148 if (first) {
149 log_test("time() returned -1, ignoring timer");
150 first = FALSE;
151 }
152 t->use = TIMER_IGNORE;
153}
154#endif
155
156/*******************************************************************/
160 struct timer *timer_new(enum timer_timetype type, enum timer_use use,
161 const char *name)
162{
163 return timer_renew(NULL, type, use, name);
164}
165
166/*******************************************************************/
180 struct timer *timer_renew(struct timer *t, enum timer_timetype type,
181 enum timer_use use, const char *name)
182{
183 if (t == NULL) {
184 t = (struct timer *)fc_malloc(sizeof(struct timer));
185#ifdef FREECIV_DEBUG
186 t->name = NULL;
187#endif
188 }
189
190 t->type = type;
191 t->use = use;
192#ifdef FREECIV_DEBUG
193 if (name != NULL) {
194 if (t->name != NULL) {
195 free(t->name);
196 }
197 t->name = fc_strdup(name);
198 }
199#endif
200 timer_clear(t);
201
202 return t;
203}
204
205/*******************************************************************/
208 void timer_destroy(struct timer *t)
209{
210 if (t != NULL) {
211
212#ifdef FREECIV_DEBUG
213 if (t->name != NULL) {
214 free(t->name);
215 }
216#endif /* FREECIV_DEBUG */
217
218 free(t);
219 }
220}
221
222/*******************************************************************/
225 static char *timer_name(struct timer *t)
226{
227#ifdef FREECIV_DEBUG
228 if (t->name != NULL) {
229 return t->name;
230 } else {
231 return "Nameless";
232 }
233#endif /* FREECIV_DEBUG */
234
235 return "-";
236}
237
238/*******************************************************************/
242 bool timer_in_use(struct timer *t)
243{
244 return (t != NULL && t->use != TIMER_IGNORE);
245}
246
247/*******************************************************************/
252 void timer_clear(struct timer *t)
253{
254 fc_assert_ret(NULL != t);
255 t->state = TIMER_STOPPED;
256 t->sec = 0.0;
257 t->usec = 0;
258}
259
260/*******************************************************************/
264 void timer_start(struct timer *t)
265{
266 fc_assert_ret(NULL != t);
267
268 if (t->use == TIMER_IGNORE) {
269 return;
270 }
271 if (t->state == TIMER_STARTED) {
272 log_error("Tried to start already started timer: %s", timer_name(t));
273 return;
274 }
275 if (t->type == TIMER_CPU) {
276 t->start.c = clock();
277 if (t->start.c == (clock_t) -1) {
278 report_clock_failed(t);
279 return;
280 }
281 } else {
282#ifdef HAVE_GETTIMEOFDAY
283 int ret = gettimeofday(&t->start.tv, NULL);
284
285 if (ret == -1) {
286 report_gettimeofday_failed(t);
287 return;
288 }
289#elif defined HAVE_FTIME
290 ftime(&t->start.tp);
291#else
292 t->start.t = time(NULL);
293 if (t->start.t == (time_t) -1) {
294 report_time_failed(t);
295 return;
296 }
297#endif
298 }
299 t->state = TIMER_STARTED;
300}
301
302/*******************************************************************/
308 void timer_stop(struct timer *t)
309{
310 fc_assert_ret(NULL != t);
311
312 if (t->use == TIMER_IGNORE) {
313 return;
314 }
315 if (t->state == TIMER_STOPPED) {
316 log_error("Tried to stop already stopped timer: %s", timer_name(t));
317 return;
318 }
319 if (t->type == TIMER_CPU) {
320 clock_t now = clock();
321
322 if (now == (clock_t) -1) {
323 report_clock_failed(t);
324 return;
325 }
326 t->sec += (now - t->start.c) / (double)CLOCKS_PER_SEC;
327 t->start.c = now;
328 } else {
329#ifdef HAVE_GETTIMEOFDAY
330 struct timeval now;
331 int ret = gettimeofday(&now, NULL);
332
333 if (ret == -1) {
334 report_gettimeofday_failed(t);
335 return;
336 }
337 t->usec += (now.tv_usec - t->start.tv.tv_usec);
338 t->sec += (now.tv_sec - t->start.tv.tv_sec);
339 if (t->usec < 0) {
340 t->usec += N_USEC_PER_SEC;
341 t->sec -= 1.0;
342 } else if (t->usec >= N_USEC_PER_SEC) {
343 long sec = t->usec / N_USEC_PER_SEC;
344
345 t->sec += sec;
346 t->usec -= sec * N_USEC_PER_SEC;
347 }
348 t->start.tv = now;
349#elif defined HAVE_FTIME
350 struct timeb now;
351
352 ftime(&now);
353 t->usec += 1000 * ((long)now.millitm - (long)t->start.tp.millitm);
354 t->sec += now.time - t->start.tp.time;
355 if (t->usec < 0) {
356 t->usec += N_USEC_PER_SEC;
357 t->sec -= 1.0;
358 } else if (t->usec >= N_USEC_PER_SEC) {
359 long sec = t->usec / N_USEC_PER_SEC;
360
361 t->sec += sec;
362 t->usec -= sec * N_USEC_PER_SEC;
363 }
364 t->start.tp = now;
365#else
366 time_t now = time(NULL);
367
368 if (now == (time_t) -1) {
369 report_time_failed(t);
370 return;
371 }
372 t->sec += difftime(now, t->start.t);
373 t->start.t = now;
374#endif
375 }
376 t->state = TIMER_STOPPED;
377}
378
379/*******************************************************************/
384 double timer_read_seconds(struct timer *t)
385{
386 fc_assert_ret_val(NULL != t, -1.0);
387
388 if (t->use == TIMER_IGNORE) {
389 return 0.0;
390 }
391 if (t->state == TIMER_STARTED) {
392 timer_stop(t);
393 t->state = TIMER_STARTED;
394 }
395
396 return t->sec + t->usec / (double)N_USEC_PER_SEC;
397}
398
399/*******************************************************************/
405 void timer_usleep_since_start(struct timer *t, long usec)
406{
407#ifdef HAVE_GETTIMEOFDAY
408 int ret;
409 struct timeval tv_now;
410 long elapsed_usec;
411 long wait_usec;
412
413 fc_assert_ret(NULL != t);
414
415 ret = gettimeofday(&tv_now, NULL);
416
417 if ((ret == -1)
418 || (t->type != TIMER_USER)
419 || (t->use != TIMER_ACTIVE)
420 || (t->state != TIMER_STARTED)) {
421 fc_usleep(usec);
422 return;
423 }
424
425 elapsed_usec =
426 (tv_now.tv_sec - t->start.tv.tv_sec) * N_USEC_PER_SEC +
427 (tv_now.tv_usec - t->start.tv.tv_usec);
428 wait_usec = usec - elapsed_usec;
429
430 if (wait_usec > 0) {
431 fc_usleep(wait_usec);
432 }
433#elif HAVE_FTIME
434 struct timeb now;
435 long elapsed_usec, wait_usec;
436
437 ftime(&now);
438
439 elapsed_usec = (now.time - t->start.tp.time) * N_USEC_PER_SEC
440 + (now.millitm - t->start.tp.millitm);
441 wait_usec = usec - elapsed_usec;
442
443 if (wait_usec > 0) {
444 fc_usleep(wait_usec);
445 }
446#else
447 fc_usleep(usec);
448#endif
449}
incite_cost
char * incite_cost
Definition comments.c:74
type
GType type
Definition repodlgs.c:1313
name
const char * name
Definition inputfile.c:127
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_strdup
#define fc_strdup(str)
Definition mem.h:43
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:104
timer::sec
double sec
Definition timing.c:92
timer::usec
long usec
Definition timing.c:93
timer::use
enum timer_use use
Definition timing.c:84
timer::c
clock_t c
Definition timing.c:98
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:641
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
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:144
timer_usleep_since_start
void timer_usleep_since_start(struct timer *t, long usec)
Definition timing.c:405
report_clock_failed
static void report_clock_failed(struct timer *t)
Definition timing.c:113
timer_clear
void timer_clear(struct timer *t)
Definition timing.c:252
timer_in_use
bool timer_in_use(struct timer *t)
Definition timing.c:242
N_USEC_PER_SEC
#define N_USEC_PER_SEC
Definition timing.c:74
timer_destroy
void timer_destroy(struct timer *t)
Definition timing.c:208
timer_name
static char * timer_name(struct timer *t)
Definition timing.c:225
timer_start
void timer_start(struct timer *t)
Definition timing.c:264
timer_stop
void timer_stop(struct timer *t)
Definition timing.c:308
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_new
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
timer_read_seconds
double timer_read_seconds(struct timer *t)
Definition timing.c:384
timer_renew
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:180
timing.h
timer_use
timer_use
Definition timing.h:45
TIMER_ACTIVE
@ TIMER_ACTIVE
Definition timing.h:46
TIMER_IGNORE
@ TIMER_IGNORE
Definition timing.h:47
timer_timetype
timer_timetype
Definition timing.h:40
TIMER_CPU
@ TIMER_CPU
Definition timing.h:41
TIMER_USER
@ TIMER_USER
Definition timing.h:42