Freeciv-3.3
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(nullptr, type, use, name);
164}
165
166/*******************************************************************/
181 enum timer_use use, const char *name)
182{
183 if (t == nullptr) {
184 t = (struct timer *)fc_malloc(sizeof(struct timer));
185#ifdef FREECIV_DEBUG
186 t->name = nullptr;
187#endif
188 }
189
190 t->type = type;
191 t->use = use;
192#ifdef FREECIV_DEBUG
193 if (name != nullptr) {
194 if (t->name != nullptr) {
195 free(t->name);
196 }
197 t->name = fc_strdup(name);
198 }
199#endif /* FREECIV_DEBUG */
200 timer_clear(t);
201
202 return t;
203}
204
205/*******************************************************************/
208void timer_destroy(struct timer *t)
209{
210 if (t != nullptr) {
211
212#ifdef FREECIV_DEBUG
213 if (t->name != nullptr) {
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 != nullptr) {
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 != nullptr && t->use != TIMER_IGNORE);
245}
246
247/*******************************************************************/
252void timer_clear(struct timer *t)
253{
254 t->state = TIMER_STOPPED;
255 t->sec = 0.0;
256 t->usec = 0;
257}
258
259/*******************************************************************/
263void timer_start(struct timer *t)
264{
265 if (t->use == TIMER_IGNORE) {
266 return;
267 }
268 if (t->state == TIMER_STARTED) {
269 log_error("Tried to start already started timer: %s", timer_name(t));
270 return;
271 }
272 if (t->type == TIMER_CPU) {
273 t->start.c = clock();
274 if (t->start.c == (clock_t) -1) {
276 return;
277 }
278 } else {
279#ifdef HAVE_GETTIMEOFDAY
280 int ret = gettimeofday(&t->start.tv, nullptr);
281
282 if (ret == -1) {
284 return;
285 }
286#elif defined HAVE_FTIME
287 ftime(&t->start.tp);
288#else
289 t->start.t = time(nullptr);
290 if (t->start.t == (time_t) -1) {
292 return;
293 }
294#endif
295 }
296 t->state = TIMER_STARTED;
297}
298
299/*******************************************************************/
305void timer_stop(struct timer *t)
306{
307 if (t->use == TIMER_IGNORE) {
308 return;
309 }
310 if (t->state == TIMER_STOPPED) {
311 log_error("Tried to stop already stopped timer: %s", timer_name(t));
312 return;
313 }
314 if (t->type == TIMER_CPU) {
315 clock_t now = clock();
316
317 if (now == (clock_t) -1) {
319 return;
320 }
321 t->sec += (now - t->start.c) / (double)CLOCKS_PER_SEC;
322 t->start.c = now;
323 } else {
324#ifdef HAVE_GETTIMEOFDAY
325 struct timeval now;
326 int ret = gettimeofday(&now, nullptr);
327
328 if (ret == -1) {
330 return;
331 }
332 t->usec += (now.tv_usec - t->start.tv.tv_usec);
333 t->sec += (now.tv_sec - t->start.tv.tv_sec);
334 if (t->usec < 0) {
335 t->usec += N_USEC_PER_SEC;
336 t->sec -= 1.0;
337 } else if (t->usec >= N_USEC_PER_SEC) {
338 long sec = t->usec / N_USEC_PER_SEC;
339
340 t->sec += sec;
341 t->usec -= sec * N_USEC_PER_SEC;
342 }
343 t->start.tv = now;
344#elif defined HAVE_FTIME
345 struct timeb now;
346
347 ftime(&now);
348 t->usec += 1000 * ((long)now.millitm - (long)t->start.tp.millitm);
349 t->sec += now.time - t->start.tp.time;
350 if (t->usec < 0) {
351 t->usec += N_USEC_PER_SEC;
352 t->sec -= 1.0;
353 } else if (t->usec >= N_USEC_PER_SEC) {
354 long sec = t->usec / N_USEC_PER_SEC;
355
356 t->sec += sec;
357 t->usec -= sec * N_USEC_PER_SEC;
358 }
359 t->start.tp = now;
360#else
361 time_t now = time(nullptr);
362
363 if (now == (time_t) -1) {
365 return;
366 }
367 t->sec += difftime(now, t->start.t);
368 t->start.t = now;
369#endif
370 }
371 t->state = TIMER_STOPPED;
372}
373
374/*******************************************************************/
379double timer_read_seconds(struct timer *t)
380{
381 if (t->use == TIMER_IGNORE) {
382 return 0.0;
383 }
384 if (t->state == TIMER_STARTED) {
385 timer_stop(t);
386 t->state = TIMER_STARTED;
387 }
388
389 return t->sec + t->usec / (double)N_USEC_PER_SEC;
390}
391
392/*******************************************************************/
398void timer_usleep_since_start(struct timer *t, long usec)
399{
400#ifdef HAVE_GETTIMEOFDAY
401 int ret;
402 struct timeval tv_now;
403 long elapsed_usec;
404 long wait_usec;
405
406 ret = gettimeofday(&tv_now, nullptr);
407
408 if ((ret == -1)
409 || (t->type != TIMER_USER)
410 || (t->use != TIMER_ACTIVE)
411 || (t->state != TIMER_STARTED)) {
412 fc_usleep(usec);
413
414 return;
415 }
416
418 (tv_now.tv_sec - t->start.tv.tv_sec) * N_USEC_PER_SEC +
419 (tv_now.tv_usec - t->start.tv.tv_usec);
420 wait_usec = usec - elapsed_usec;
421
422 if (wait_usec > 0) {
424 }
425#elif HAVE_FTIME
426 struct timeb now;
428
429 ftime(&now);
430
431 elapsed_usec = (now.time - t->start.tp.time) * N_USEC_PER_SEC
432 + (now.millitm - t->start.tp.millitm);
433 wait_usec = usec - elapsed_usec;
434
435 if (wait_usec > 0) {
437 }
438#else
439 fc_usleep(usec);
440#endif
441}
char * incite_cost
Definition comments.c:76
GType type
Definition repodlgs.c:1313
const char * name
Definition inputfile.c:127
#define log_test
Definition log.h:137
#define log_error(message,...)
Definition log.h:104
#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:639
#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:398
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:263
void timer_stop(struct timer *t)
Definition timing.c:305
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:379
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