source: trunk/essentials/net-misc/wget/src/ptimer.c

Last change on this file was 3440, checked in by bird, 18 years ago

wget 1.10.2

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