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
80
81struct timer {
82 /* type: */
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 {
99#ifdef HAVE_GETTIMEOFDAY
100 struct timeval tv;
101#elif HAVE_FTIME
102 struct timeb tp;
103#else
105#endif
107};
108
109/*******************************************************************/
113static 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/*******************************************************************/
144static 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/*******************************************************************/
161 const char *name)
162{
163 return timer_renew(NULL, type, use, name);
164}
165
166/*******************************************************************/
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/*******************************************************************/
208void 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/*******************************************************************/
225static 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/*******************************************************************/
242bool timer_in_use(struct timer *t)
243{
244 return (t != NULL && t->use != TIMER_IGNORE);
245}
246
247/*******************************************************************/
252void 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/*******************************************************************/
264void 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) {
279 return;
280 }
281 } else {
282#ifdef HAVE_GETTIMEOFDAY
283 int ret = gettimeofday(&t->start.tv, NULL);
284
285 if (ret == -1) {
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) {
295 return;
296 }
297#endif
298 }
299 t->state = TIMER_STARTED;
300}
301
302/*******************************************************************/
308void 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) {
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) {
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) {
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/*******************************************************************/
384double 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/*******************************************************************/
405void 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
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
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) {
432 }
433#elif HAVE_FTIME
434 struct timeb now;
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) {
445 }
446#else
447 fc_usleep(usec);
448#endif
449}
char * incite_cost
Definition comments.c:75
GType type
Definition repodlgs.c:1313
const char * name
Definition inputfile.c:127
#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_strdup(str)
Definition mem.h:43
#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:104
double sec
Definition timing.c:92
long usec
Definition timing.c:93
enum timer_use use
Definition timing.c:84
clock_t c
Definition timing.c:98
enum timer_state state
Definition timing.c:85
union timer::@11 start
void fc_usleep(unsigned long usec)
Definition support.c:641
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define CLOCKS_PER_SEC
Definition timing.c:70
static void report_time_failed(struct timer *t)
Definition timing.c:144
void timer_usleep_since_start(struct timer *t, long usec)
Definition timing.c:405
static void report_clock_failed(struct timer *t)
Definition timing.c:113
void timer_clear(struct timer *t)
Definition timing.c:252
bool timer_in_use(struct timer *t)
Definition timing.c:242
#define N_USEC_PER_SEC
Definition timing.c:74
void timer_destroy(struct timer *t)
Definition timing.c:208
static char * timer_name(struct timer *t)
Definition timing.c:225
void timer_start(struct timer *t)
Definition timing.c:264
void timer_stop(struct timer *t)
Definition timing.c:308
timer_state
Definition timing.c:76
@ TIMER_STARTED
Definition timing.c:77
@ TIMER_STOPPED
Definition timing.c:78
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
double timer_read_seconds(struct timer *t)
Definition timing.c:384
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:180
timer_use
Definition timing.h:45
@ TIMER_ACTIVE
Definition timing.h:46
@ TIMER_IGNORE
Definition timing.h:47
timer_timetype
Definition timing.h:40
@ TIMER_CPU
Definition timing.h:41
@ TIMER_USER
Definition timing.h:42