]> sjero.net Git - wget/blob - src/ptimer.c
[svn] Remove the unused "initialized" field from struct ptimer.
[wget] / src / ptimer.c
1 /* Portable timers.
2    Copyright (C) 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 /* This file implements "portable timers" (ptimers), objects that
31    measure elapsed time using the primitives most appropriate for the
32    underlying operating system.  The entry points are:
33
34      ptimer_new     -- creates a timer.
35      ptimer_reset   -- resets the timer's elapsed time to zero.
36      ptimer_measure -- measure and return the time elapsed since
37                        creation or last reset.
38      ptimer_read    -- reads the last measured elapsed value.
39      ptimer_destroy -- destroy the timer.
40      ptimer_granularity -- returns the approximate granularity of the timers.
41
42    Timers measure time in milliseconds, but the timings they return
43    are floating point numbers, so they can carry as much precision as
44    the underlying system timer supports.  For example, to measure the
45    time it takes to run a loop, you can use something like:
46
47      ptimer *tmr = ptimer_new ();
48      while (...)
49        ... loop ...
50      double msecs = ptimer_measure ();
51      printf ("The loop took %.2f ms\n", msecs);  */
52
53 #include <config.h>
54
55 #include <stdio.h>
56 #include <stdlib.h>
57 #ifdef HAVE_STRING_H
58 # include <string.h>
59 #else  /* not HAVE_STRING_H */
60 # include <strings.h>
61 #endif /* not HAVE_STRING_H */
62 #include <sys/types.h>
63 #include <errno.h>
64 #ifdef HAVE_UNISTD_H
65 # include <unistd.h>
66 #endif
67 #include <assert.h>
68
69 #include "wget.h"
70 #include "ptimer.h"
71
72 #ifndef errno
73 extern int errno;
74 #endif
75
76 /* Depending on the OS and availability of gettimeofday(), one and
77    only one of PTIMER_POSIX, PTIMER_GETTIMEOFDAY, PTIMER_WINDOWS, or
78    PTIMER_TIME will be defined.  */
79
80 #undef PTIMER_POSIX
81 #undef PTIMER_GETTIMEOFDAY
82 #undef PTIMER_TIME
83 #undef PTIMER_WINDOWS
84
85 #ifdef WINDOWS
86 # define PTIMER_WINDOWS         /* use Windows timers */
87 #else
88 # if _POSIX_TIMERS > 0
89 #  define PTIMER_POSIX          /* use POSIX timers (clock_gettime) */
90 # else
91 #  ifdef HAVE_GETTIMEOFDAY
92 #   define PTIMER_GETTIMEOFDAY  /* use gettimeofday */
93 #  else
94 #   define PTIMER_TIME
95 #  endif
96 # endif
97 #endif
98
99 #ifdef PTIMER_POSIX
100 /* Elapsed time measurement using POSIX timers: system time is held in
101    struct timespec, time is retrieved using clock_gettime, and
102    resolution using clock_getres.
103
104    This method is used on Unix systems that implement POSIX
105    timers.  */
106
107 typedef struct timespec ptimer_system_time;
108
109 #define IMPL_init posix_init
110 #define IMPL_measure posix_measure
111 #define IMPL_diff posix_diff
112 #define IMPL_resolution posix_resolution
113
114 /* clock_id to use for POSIX clocks.  This tries to use
115    CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise.  */
116 static int posix_clock_id;
117
118 /* Resolution of the clock, in milliseconds. */
119 static double posix_millisec_resolution;
120
121 /* Decide which clock_id to use.  */
122
123 static void
124 posix_init (void)
125 {
126   /* List of clocks we want to support: some systems support monotonic
127      clocks, Solaris has "high resolution" clock (sometimes
128      unavailable except to superuser), and all should support the
129      real-time clock.  */
130 #define NO_SYSCONF_CHECK -1
131   static const struct {
132     int id;
133     int sysconf_name;
134   } clocks[] = {
135 #if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
136     { CLOCK_MONOTONIC, _SC_MONOTONIC_CLOCK },
137 #endif
138 #ifdef CLOCK_HIGHRES
139     { CLOCK_HIGHRES, NO_SYSCONF_CHECK },
140 #endif
141     { CLOCK_REALTIME, NO_SYSCONF_CHECK },
142   };
143   int i;
144
145   /* Determine the clock we can use.  For a clock to be usable, it
146      must be confirmed with sysconf (where applicable) and with
147      clock_getres.  If no clock is found, CLOCK_REALTIME is used.  */
148
149   for (i = 0; i < countof (clocks); i++)
150     {
151       struct timespec r;
152       if (clocks[i].sysconf_name != NO_SYSCONF_CHECK)
153         if (sysconf (clocks[i].sysconf_name) < 0)
154           continue;             /* sysconf claims this clock is unavailable */
155       if (clock_getres (clocks[i].id, &r) < 0)
156         continue;               /* clock_getres doesn't work for this clock */
157       posix_clock_id = clocks[i].id;
158       posix_millisec_resolution = r.tv_sec * 1000.0 + r.tv_nsec / 1000000.0;
159       /* Guard against broken clock_getres returning nonsensical
160          values.  */
161       if (posix_millisec_resolution == 0)
162         posix_millisec_resolution = 1;
163       break;
164     }
165   if (i == countof (clocks))
166     {
167       /* If no clock was found, it means that clock_getres failed for
168          the realtime clock.  */
169       logprintf (LOG_NOTQUIET, _("Cannot get REALTIME clock frequency: %s\n"),
170                  strerror (errno));
171       /* Use CLOCK_REALTIME, but invent a plausible resolution. */
172       posix_clock_id = CLOCK_REALTIME;
173       posix_millisec_resolution = 1;
174     }
175 }
176
177 static inline void
178 posix_measure (ptimer_system_time *pst)
179 {
180   clock_gettime (posix_clock_id, pst);
181 }
182
183 static inline double
184 posix_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
185 {
186   return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
187           + (pst1->tv_nsec - pst2->tv_nsec) / 1000000.0);
188 }
189
190 static inline double
191 posix_resolution (void)
192 {
193   return posix_millisec_resolution;
194 }
195 #endif  /* PTIMER_POSIX */
196
197 #ifdef PTIMER_GETTIMEOFDAY
198 /* Elapsed time measurement using gettimeofday: system time is held in
199    struct timeval, retrieved using gettimeofday, and resolution is
200    unknown.
201
202    This method is used Unix systems without POSIX timers.  */
203
204 typedef struct timeval ptimer_system_time;
205
206 #define IMPL_measure gettimeofday_measure
207 #define IMPL_diff gettimeofday_diff
208 #define IMPL_resolution gettimeofday_resolution
209
210 static inline void
211 gettimeofday_measure (ptimer_system_time *pst)
212 {
213   gettimeofday (pst, NULL);
214 }
215
216 static inline double
217 gettimeofday_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
218 {
219   return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
220           + (pst1->tv_usec - pst2->tv_usec) / 1000.0);
221 }
222
223 static inline double
224 gettimeofday_resolution (void)
225 {
226   /* Granularity of gettimeofday varies wildly between architectures.
227      However, it appears that on modern machines it tends to be better
228      than 1ms.  Assume 100 usecs.  */
229   return 0.1;
230 }
231 #endif  /* PTIMER_GETTIMEOFDAY */
232
233 #ifdef PTIMER_TIME
234 /* Elapsed time measurement using the time(2) call: system time is
235    held in time_t, retrieved using time, and resolution is 1 second.
236
237    This method is a catch-all for non-Windows systems without
238    gettimeofday -- e.g. DOS or really old or non-standard Unix
239    systems.  */
240
241 typedef time_t ptimer_system_time;
242
243 #define IMPL_measure time_measure
244 #define IMPL_diff time_diff
245 #define IMPL_resolution time_resolution
246
247 static inline void
248 time_measure (ptimer_system_time *pst)
249 {
250   time (pst);
251 }
252
253 static inline double
254 time_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
255 {
256   return 1000.0 * (*pst1 - *pst2);
257 }
258
259 static inline double
260 time_resolution (void)
261 {
262   return 1;
263 }
264 #endif  /* PTIMER_TIME */
265
266 #ifdef PTIMER_WINDOWS
267 /* Elapsed time measurement on Windows: where high-resolution timers
268    are available, time is stored in a LARGE_INTEGER and retrieved
269    using QueryPerformanceCounter.  Otherwise, it is stored in a DWORD
270    and retrieved using GetTickCount.
271
272    This method is used on Windows.  */
273
274 typedef union {
275   DWORD lores;          /* In case GetTickCount is used */
276   LARGE_INTEGER hires;  /* In case high-resolution timer is used */
277 } ptimer_system_time;
278
279 #define IMPL_init windows_init
280 #define IMPL_measure windows_measure
281 #define IMPL_diff windows_diff
282 #define IMPL_resolution windows_resolution
283
284 /* Whether high-resolution timers are used.  Set by ptimer_initialize_once
285    the first time ptimer_new is called. */
286 static int windows_hires_timers;
287
288 /* Frequency of high-resolution timers -- number of updates per
289    millisecond.  Calculated the first time ptimer_new is called
290    provided that high-resolution timers are available. */
291 static double windows_hires_msfreq;
292
293 static void
294 windows_init (void)
295 {
296   LARGE_INTEGER freq;
297   freq.QuadPart = 0;
298   QueryPerformanceFrequency (&freq);
299   if (freq.QuadPart != 0)
300     {
301       windows_hires_timers = 1;
302       windows_hires_msfreq = (double) freq.QuadPart / 1000.0;
303     }
304 }
305
306 static inline void
307 windows_measure (ptimer_system_time *pst)
308 {
309   if (windows_hires_timers)
310     QueryPerformanceCounter (&pst->hires);
311   else
312     /* Where hires counters are not available, use GetTickCount rather
313        GetSystemTime, because it is unaffected by clock skew and
314        simpler to use.  Note that overflows don't affect us because we
315        never use absolute values of the ticker, only the
316        differences.  */
317     pst->lores = GetTickCount ();
318 }
319
320 static inline double
321 windows_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
322 {
323   if (windows_hires_timers)
324     return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_msfreq;
325   else
326     return pst1->lores - pst2->lores;
327 }
328
329 static double
330 windows_resolution (void)
331 {
332   if (windows_hires_timers)
333     return 1.0 / windows_hires_msfreq;
334   else
335     return 10;                  /* according to MSDN */
336 }
337 #endif  /* PTIMER_WINDOWS */
338 \f
339 /* The code below this point is independent of timer implementation. */
340
341 struct ptimer {
342   /* The starting point in time which, subtracted from the current
343      time, yields elapsed time. */
344   ptimer_system_time start;
345
346   /* The most recent elapsed time, calculated by ptimer_measure().
347      Measured in milliseconds.  */
348   double elapsed_last;
349
350   /* Approximately, the time elapsed between the true start of the
351      measurement and the time represented by START.  This is used for
352      adjustment when clock skew is detected.  */
353   double elapsed_pre_start;
354 };
355
356 /* Allocate a new timer and reset it.  Return the new timer. */
357
358 struct ptimer *
359 ptimer_new (void)
360 {
361   struct ptimer *pt = xnew0 (struct ptimer);
362 #ifdef IMPL_init
363   static int init_done;
364   if (!init_done)
365     {
366       init_done = 1;
367       IMPL_init ();
368     }
369 #endif
370   ptimer_reset (pt);
371   return pt;
372 }
373
374 /* Free the resources associated with the timer.  Its further use is
375    prohibited.  */
376
377 void
378 ptimer_destroy (struct ptimer *pt)
379 {
380   xfree (pt);
381 }
382
383 /* Reset timer PT.  This establishes the starting point from which
384    ptimer_read() will return the number of elapsed milliseconds.
385    It is allowed to reset a previously used timer.  */
386
387 void
388 ptimer_reset (struct ptimer *pt)
389 {
390   /* Set the start time to the current time. */
391   IMPL_measure (&pt->start);
392   pt->elapsed_last = 0;
393   pt->elapsed_pre_start = 0;
394 }
395
396 /* Measure the elapsed time since timer creation/reset and return it
397    to the caller.  The value remains stored for further reads by
398    ptimer_read.
399
400    This function causes the timer to call gettimeofday (or time(),
401    etc.) to update its idea of current time.  To get the elapsed
402    interval in milliseconds, use ptimer_read.
403
404    This function handles clock skew, i.e. time that moves backwards is
405    ignored.  */
406
407 double
408 ptimer_measure (struct ptimer *pt)
409 {
410   ptimer_system_time now;
411   double elapsed;
412
413   IMPL_measure (&now);
414   elapsed = pt->elapsed_pre_start + IMPL_diff (&now, &pt->start);
415
416   /* Ideally we'd just return the difference between NOW and
417      pt->start.  However, the system timer can be set back, and we
418      could return a value smaller than when we were last called, even
419      a negative value.  Both of these would confuse the callers, which
420      expect us to return monotonically nondecreasing values.
421
422      Therefore: if ELAPSED is smaller than its previous known value,
423      we reset pt->start to the current time and effectively start
424      measuring from this point.  But since we don't want the elapsed
425      value to start from zero, we set elapsed_pre_start to the last
426      elapsed time and increment all future calculations by that
427      amount.
428
429      This cannot happen with Windows and POSIX monotonic/highres
430      timers, but the check is not expensive.  */
431
432   if (elapsed < pt->elapsed_last)
433     {
434       pt->start = now;
435       pt->elapsed_pre_start = pt->elapsed_last;
436       elapsed = pt->elapsed_last;
437     }
438
439   pt->elapsed_last = elapsed;
440   return elapsed;
441 }
442
443 /* Return the elapsed time in milliseconds between the last call to
444    ptimer_reset and the last call to ptimer_update.  */
445
446 double
447 ptimer_read (const struct ptimer *pt)
448 {
449   return pt->elapsed_last;
450 }
451
452 /* Return the assessed resolution of the timer implementation, in
453    milliseconds.  This is used by code that tries to substitute a
454    better value for timers that have returned zero.  */
455
456 double
457 ptimer_resolution (void)
458 {
459   return IMPL_resolution ();
460 }