mirror of
https://github.com/mirror/wget.git
synced 2025-03-10 17:50:15 +08:00
[svn] Better selection of POSIX clocks.
This commit is contained in:
parent
ab05800310
commit
14a2d25b2e
@ -1,3 +1,20 @@
|
|||||||
|
2005-04-08 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
|
* ptimer.c (posix_init): Be smarter about choosing clocks. In
|
||||||
|
decreasing order of preference, use CLOCK_MONOTONIC,
|
||||||
|
CLOCK_HIGHRES, and CLOCK_REALTIME.
|
||||||
|
(ptimer_allocate): Removed.
|
||||||
|
|
||||||
|
* ptimer.c: Refactor the code by cleanly separating the
|
||||||
|
architecture-dependent code from the architecture-independent
|
||||||
|
code.
|
||||||
|
|
||||||
|
2005-04-08 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
|
* ptimer.c (ptimer_init): Explicitly check that
|
||||||
|
_POSIX_MONOTONIC_CLOCK is *both* defined and >=0. (Undefined
|
||||||
|
symbols are >=0.)
|
||||||
|
|
||||||
2005-04-08 Hrvoje Niksic <hniksic@xemacs.org>
|
2005-04-08 Hrvoje Niksic <hniksic@xemacs.org>
|
||||||
|
|
||||||
* ptimer.c (ptimer_diff): Fix typo affecting Windows build.
|
* ptimer.c (ptimer_diff): Fix typo affecting Windows build.
|
||||||
|
441
src/ptimer.c
441
src/ptimer.c
@ -73,13 +73,8 @@ extern int errno;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Depending on the OS and availability of gettimeofday(), one and
|
/* Depending on the OS and availability of gettimeofday(), one and
|
||||||
only one of PTIMER_WINDOWS, PTIMER_GETTIMEOFDAY, or PTIMER_TIME will
|
only one of PTIMER_POSIX, PTIMER_GETTIMEOFDAY, PTIMER_WINDOWS, or
|
||||||
be defined.
|
PTIMER_TIME will be defined. */
|
||||||
|
|
||||||
Virtually all modern Unix systems will define PTIMER_GETTIMEOFDAY;
|
|
||||||
Windows will use PTIMER_WINDOWS. PTIMER_TIME is a catch-all method
|
|
||||||
for non-Windows systems without gettimeofday, such as DOS or really
|
|
||||||
old Unix-like systems. */
|
|
||||||
|
|
||||||
#undef PTIMER_POSIX
|
#undef PTIMER_POSIX
|
||||||
#undef PTIMER_GETTIMEOFDAY
|
#undef PTIMER_GETTIMEOFDAY
|
||||||
@ -100,26 +95,247 @@ extern int errno;
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The type ptimer_system_time holds system time. */
|
|
||||||
|
|
||||||
#ifdef PTIMER_POSIX
|
#ifdef PTIMER_POSIX
|
||||||
|
/* Elapsed time measurement using POSIX timers: system time is held in
|
||||||
|
struct timespec, time is retrieved using clock_gettime, and
|
||||||
|
resolution using clock_getres.
|
||||||
|
|
||||||
|
This method is used on Unix systems that implement POSIX
|
||||||
|
timers. */
|
||||||
|
|
||||||
typedef struct timespec ptimer_system_time;
|
typedef struct timespec ptimer_system_time;
|
||||||
|
|
||||||
|
#define IMPL_init posix_init
|
||||||
|
#define IMPL_measure posix_measure
|
||||||
|
#define IMPL_diff posix_diff
|
||||||
|
#define IMPL_resolution posix_resolution
|
||||||
|
|
||||||
|
/* clock_id to use for POSIX clocks. This tries to use
|
||||||
|
CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise. */
|
||||||
|
static int posix_clock_id;
|
||||||
|
|
||||||
|
/* Resolution of the clock, in milliseconds. */
|
||||||
|
static double posix_millisec_resolution;
|
||||||
|
|
||||||
|
/* Decide which clock_id to use. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
posix_init (void)
|
||||||
|
{
|
||||||
|
/* List of clocks we want to support: some systems support monotonic
|
||||||
|
clocks, Solaris has "high resolution" clock (sometimes
|
||||||
|
unavailable except to superuser), and all should support the
|
||||||
|
real-time clock. */
|
||||||
|
#define NO_SYSCONF_CHECK -1
|
||||||
|
static const struct {
|
||||||
|
int id;
|
||||||
|
int sysconf_name;
|
||||||
|
} clocks[] = {
|
||||||
|
#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
|
||||||
|
{ CLOCK_MONOTONIC, _SC_MONOTONIC_CLOCK },
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CLOCK_HIGHRES
|
||||||
|
{ CLOCK_HIGHRES, NO_SYSCONF_CHECK },
|
||||||
|
#endif
|
||||||
|
{ CLOCK_REALTIME, NO_SYSCONF_CHECK },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Determine the clock we can use. For a clock to be usable, it
|
||||||
|
must be confirmed with sysconf (where applicable) and with
|
||||||
|
clock_getres. If no clock is found, CLOCK_REALTIME is used. */
|
||||||
|
|
||||||
|
for (i = 0; i < countof (clocks); i++)
|
||||||
|
{
|
||||||
|
struct timespec r;
|
||||||
|
if (clocks[i].sysconf_name != NO_SYSCONF_CHECK)
|
||||||
|
if (sysconf (clocks[i].sysconf_name) < 0)
|
||||||
|
continue; /* sysconf claims this clock is unavailable */
|
||||||
|
if (clock_getres (clocks[i].id, &r) < 0)
|
||||||
|
continue; /* clock_getres doesn't work for this clock */
|
||||||
|
posix_clock_id = clocks[i].id;
|
||||||
|
posix_millisec_resolution = r.tv_sec * 1000.0 + r.tv_nsec / 1000000.0;
|
||||||
|
/* Guard against broken clock_getres returning nonsensical
|
||||||
|
values. */
|
||||||
|
if (posix_millisec_resolution == 0)
|
||||||
|
posix_millisec_resolution = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == countof (clocks))
|
||||||
|
{
|
||||||
|
/* If no clock was found, it means that clock_getres failed for
|
||||||
|
the realtime clock. */
|
||||||
|
logprintf (LOG_NOTQUIET, _("Cannot get REALTIME clock frequency: %s\n"),
|
||||||
|
strerror (errno));
|
||||||
|
/* Use CLOCK_REALTIME, but invent a plausible resolution. */
|
||||||
|
posix_clock_id = CLOCK_REALTIME;
|
||||||
|
posix_millisec_resolution = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
posix_measure (ptimer_system_time *pst)
|
||||||
|
{
|
||||||
|
clock_gettime (posix_clock_id, pst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
posix_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
|
||||||
|
{
|
||||||
|
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
|
||||||
|
+ (pst1->tv_nsec - pst2->tv_nsec) / 1000000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
posix_resolution (void)
|
||||||
|
{
|
||||||
|
return posix_millisec_resolution;
|
||||||
|
}
|
||||||
|
#endif /* PTIMER_POSIX */
|
||||||
|
|
||||||
#ifdef PTIMER_GETTIMEOFDAY
|
#ifdef PTIMER_GETTIMEOFDAY
|
||||||
|
/* Elapsed time measurement using gettimeofday: system time is held in
|
||||||
|
struct timeval, retrieved using gettimeofday, and resolution is
|
||||||
|
unknown.
|
||||||
|
|
||||||
|
This method is used Unix systems without POSIX timers. */
|
||||||
|
|
||||||
typedef struct timeval ptimer_system_time;
|
typedef struct timeval ptimer_system_time;
|
||||||
#endif
|
|
||||||
|
#define IMPL_measure gettimeofday_measure
|
||||||
|
#define IMPL_diff gettimeofday_diff
|
||||||
|
#define IMPL_resolution gettimeofday_resolution
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
gettimeofday_measure (ptimer_system_time *pst)
|
||||||
|
{
|
||||||
|
gettimeofday (pst, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
gettimeofday_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
|
||||||
|
{
|
||||||
|
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
|
||||||
|
+ (pst1->tv_usec - pst2->tv_usec) / 1000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
gettimeofday_resolution (void)
|
||||||
|
{
|
||||||
|
/* Granularity of gettimeofday varies wildly between architectures.
|
||||||
|
However, it appears that on modern machines it tends to be better
|
||||||
|
than 1ms. Assume 100 usecs. */
|
||||||
|
return 0.1;
|
||||||
|
}
|
||||||
|
#endif /* PTIMER_GETTIMEOFDAY */
|
||||||
|
|
||||||
#ifdef PTIMER_TIME
|
#ifdef PTIMER_TIME
|
||||||
|
/* Elapsed time measurement using the time(2) call: system time is
|
||||||
|
held in time_t, retrieved using time, and resolution is 1 second.
|
||||||
|
|
||||||
|
This method is a catch-all for non-Windows systems without
|
||||||
|
gettimeofday -- e.g. DOS or really old or non-standard Unix
|
||||||
|
systems. */
|
||||||
|
|
||||||
typedef time_t ptimer_system_time;
|
typedef time_t ptimer_system_time;
|
||||||
#endif
|
|
||||||
|
#define IMPL_measure time_measure
|
||||||
|
#define IMPL_diff time_diff
|
||||||
|
#define IMPL_resolution time_resolution
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
time_measure (ptimer_system_time *pst)
|
||||||
|
{
|
||||||
|
time (pst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
time_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
|
||||||
|
{
|
||||||
|
return 1000.0 * (*pst1 - *pst2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
time_resolution (void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* PTIMER_TIME */
|
||||||
|
|
||||||
#ifdef PTIMER_WINDOWS
|
#ifdef PTIMER_WINDOWS
|
||||||
|
/* Elapsed time measurement on Windows: where high-resolution timers
|
||||||
|
are available, time is stored in a LARGE_INTEGER and retrieved
|
||||||
|
using QueryPerformanceCounter. Otherwise, it is stored in a DWORD
|
||||||
|
and retrieved using GetTickCount.
|
||||||
|
|
||||||
|
This method is used on Windows. */
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
DWORD lores; /* In case GetTickCount is used */
|
DWORD lores; /* In case GetTickCount is used */
|
||||||
LARGE_INTEGER hires; /* In case high-resolution timer is used */
|
LARGE_INTEGER hires; /* In case high-resolution timer is used */
|
||||||
} ptimer_system_time;
|
} ptimer_system_time;
|
||||||
#endif
|
|
||||||
|
#define IMPL_init windows_init
|
||||||
|
#define IMPL_measure windows_measure
|
||||||
|
#define IMPL_diff windows_diff
|
||||||
|
#define IMPL_resolution windows_resolution
|
||||||
|
|
||||||
|
/* Whether high-resolution timers are used. Set by ptimer_initialize_once
|
||||||
|
the first time ptimer_new is called. */
|
||||||
|
static int windows_hires_timers;
|
||||||
|
|
||||||
|
/* Frequency of high-resolution timers -- number of updates per
|
||||||
|
millisecond. Calculated the first time ptimer_new is called
|
||||||
|
provided that high-resolution timers are available. */
|
||||||
|
static double windows_hires_msfreq;
|
||||||
|
|
||||||
|
static void
|
||||||
|
windows_init (void)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER freq;
|
||||||
|
freq.QuadPart = 0;
|
||||||
|
QueryPerformanceFrequency (&freq);
|
||||||
|
if (freq.QuadPart != 0)
|
||||||
|
{
|
||||||
|
windows_hires_timers = 1;
|
||||||
|
windows_hires_msfreq = (double) freq.QuadPart / 1000.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
windows_measure (ptimer_system_time *pst)
|
||||||
|
{
|
||||||
|
if (windows_hires_timers)
|
||||||
|
QueryPerformanceCounter (&pst->hires);
|
||||||
|
else
|
||||||
|
/* Where hires counters are not available, use GetTickCount rather
|
||||||
|
GetSystemTime, because it is unaffected by clock skew and
|
||||||
|
simpler to use. Note that overflows don't affect us because we
|
||||||
|
never use absolute values of the ticker, only the
|
||||||
|
differences. */
|
||||||
|
pst->lores = GetTickCount ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
|
windows_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
|
||||||
|
{
|
||||||
|
if (windows_hires_timers)
|
||||||
|
return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_msfreq;
|
||||||
|
else
|
||||||
|
return pst1->lores - pst2->lores;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
windows_resolution (void)
|
||||||
|
{
|
||||||
|
if (windows_hires_timers)
|
||||||
|
return 1.0 / windows_hires_msfreq;
|
||||||
|
else
|
||||||
|
return 10; /* according to MSDN */
|
||||||
|
}
|
||||||
|
#endif /* PTIMER_WINDOWS */
|
||||||
|
|
||||||
|
/* The code below this point is independent of timer implementation. */
|
||||||
|
|
||||||
struct ptimer {
|
struct ptimer {
|
||||||
/* Whether the start time has been set. */
|
/* Whether the start time has been set. */
|
||||||
@ -134,108 +350,25 @@ struct ptimer {
|
|||||||
double elapsed_last;
|
double elapsed_last;
|
||||||
|
|
||||||
/* Approximately, the time elapsed between the true start of the
|
/* Approximately, the time elapsed between the true start of the
|
||||||
measurement and the time represented by START. */
|
measurement and the time represented by START. This is used for
|
||||||
|
adjustment when clock skew is detected. */
|
||||||
double elapsed_pre_start;
|
double elapsed_pre_start;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef PTIMER_WINDOWS
|
|
||||||
/* Whether high-resolution timers are used. Set by ptimer_initialize_once
|
|
||||||
the first time ptimer_allocate is called. */
|
|
||||||
static int windows_hires_timers;
|
|
||||||
|
|
||||||
/* Frequency of high-resolution timers -- number of updates per
|
|
||||||
millisecond. Calculated the first time ptimer_allocate is called
|
|
||||||
provided that high-resolution timers are available. */
|
|
||||||
static double windows_hires_msfreq;
|
|
||||||
|
|
||||||
/* The first time a timer is created, determine whether to use
|
|
||||||
high-resolution timers. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ptimer_init (void)
|
|
||||||
{
|
|
||||||
LARGE_INTEGER freq;
|
|
||||||
freq.QuadPart = 0;
|
|
||||||
QueryPerformanceFrequency (&freq);
|
|
||||||
if (freq.QuadPart != 0)
|
|
||||||
{
|
|
||||||
windows_hires_timers = 1;
|
|
||||||
windows_hires_msfreq = (double) freq.QuadPart / 1000.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#define PTIMER_INIT_DEFINED
|
|
||||||
#endif /* PTIMER_WINDOWS */
|
|
||||||
|
|
||||||
#ifdef PTIMER_POSIX
|
|
||||||
|
|
||||||
/* clock_id to use for POSIX clocks. This tries to use
|
|
||||||
CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise. */
|
|
||||||
static int posix_clock_id;
|
|
||||||
|
|
||||||
/* Resolution of the clock, in milliseconds. */
|
|
||||||
static double posix_resolution;
|
|
||||||
|
|
||||||
/* Check whether the monotonic clock is available, and retrieve POSIX
|
|
||||||
timer resolution. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ptimer_init (void)
|
|
||||||
{
|
|
||||||
struct timespec res;
|
|
||||||
|
|
||||||
#if _POSIX_MONOTONIC_CLOCK >= 0 /* -1 means not supported */
|
|
||||||
if (sysconf (_SC_MONOTONIC_CLOCK) > 0)
|
|
||||||
posix_clock_id = CLOCK_MONOTONIC;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
posix_clock_id = CLOCK_REALTIME;
|
|
||||||
|
|
||||||
if (clock_getres (posix_clock_id, &res) < 0)
|
|
||||||
{
|
|
||||||
logprintf (LOG_NOTQUIET, _("Cannot read clock resolution: %s\n"),
|
|
||||||
strerror (errno));
|
|
||||||
/* Assume 1 ms resolution */
|
|
||||||
res.tv_sec = 0;
|
|
||||||
res.tv_nsec = 1000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
posix_resolution = res.tv_sec * 1000.0 + res.tv_nsec / 1000000.0;
|
|
||||||
/* Guard against clock_getres reporting 0 resolution; after all, it
|
|
||||||
can be used for division. */
|
|
||||||
if (posix_resolution == 0)
|
|
||||||
posix_resolution = 1;
|
|
||||||
}
|
|
||||||
#define PTIMER_INIT_DEFINED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allocate a timer. Calling ptimer_read on the timer will return
|
|
||||||
zero. It is not legal to call ptimer_measure with a freshly
|
|
||||||
allocated timer -- use ptimer_reset first. */
|
|
||||||
|
|
||||||
struct ptimer *
|
|
||||||
ptimer_allocate (void)
|
|
||||||
{
|
|
||||||
struct ptimer *wt;
|
|
||||||
|
|
||||||
#ifdef PTIMER_INIT_DEFINED
|
|
||||||
static int init_done;
|
|
||||||
if (!init_done)
|
|
||||||
{
|
|
||||||
init_done = 1;
|
|
||||||
ptimer_init ();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wt = xnew0 (struct ptimer);
|
|
||||||
return wt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate a new timer and reset it. Return the new timer. */
|
/* Allocate a new timer and reset it. Return the new timer. */
|
||||||
|
|
||||||
struct ptimer *
|
struct ptimer *
|
||||||
ptimer_new (void)
|
ptimer_new (void)
|
||||||
{
|
{
|
||||||
struct ptimer *wt = ptimer_allocate ();
|
struct ptimer *wt = xnew0 (struct ptimer);
|
||||||
|
#ifdef IMPL_init
|
||||||
|
static int init_done;
|
||||||
|
if (!init_done)
|
||||||
|
{
|
||||||
|
init_done = 1;
|
||||||
|
IMPL_init ();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ptimer_reset (wt);
|
ptimer_reset (wt);
|
||||||
return wt;
|
return wt;
|
||||||
}
|
}
|
||||||
@ -249,39 +382,6 @@ ptimer_destroy (struct ptimer *wt)
|
|||||||
xfree (wt);
|
xfree (wt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store system time to PST. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ptimer_sys_set (ptimer_system_time *pst)
|
|
||||||
{
|
|
||||||
#ifdef PTIMER_POSIX
|
|
||||||
clock_gettime (posix_clock_id, pst);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_GETTIMEOFDAY
|
|
||||||
gettimeofday (pst, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_TIME
|
|
||||||
time (pst);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_WINDOWS
|
|
||||||
if (windows_hires_timers)
|
|
||||||
{
|
|
||||||
QueryPerformanceCounter (&pst->hires);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Where hires counters are not available, use GetTickCount rather
|
|
||||||
GetSystemTime, because it is unaffected by clock skew and simpler
|
|
||||||
to use. Note that overflows don't affect us because we never use
|
|
||||||
absolute values of the ticker, only the differences. */
|
|
||||||
pst->lores = GetTickCount ();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset timer WT. This establishes the starting point from which
|
/* Reset timer WT. This establishes the starting point from which
|
||||||
ptimer_read() will return the number of elapsed milliseconds.
|
ptimer_read() will return the number of elapsed milliseconds.
|
||||||
It is allowed to reset a previously used timer. */
|
It is allowed to reset a previously used timer. */
|
||||||
@ -290,37 +390,12 @@ void
|
|||||||
ptimer_reset (struct ptimer *wt)
|
ptimer_reset (struct ptimer *wt)
|
||||||
{
|
{
|
||||||
/* Set the start time to the current time. */
|
/* Set the start time to the current time. */
|
||||||
ptimer_sys_set (&wt->start);
|
IMPL_measure (&wt->start);
|
||||||
wt->elapsed_last = 0;
|
wt->elapsed_last = 0;
|
||||||
wt->elapsed_pre_start = 0;
|
wt->elapsed_pre_start = 0;
|
||||||
wt->initialized = 1;
|
wt->initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double
|
|
||||||
ptimer_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
|
|
||||||
{
|
|
||||||
#ifdef PTIMER_POSIX
|
|
||||||
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
|
|
||||||
+ (pst1->tv_nsec - pst2->tv_nsec) / 1000000.0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_GETTIMEOFDAY
|
|
||||||
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
|
|
||||||
+ (pst1->tv_usec - pst2->tv_usec) / 1000.0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_TIME
|
|
||||||
return 1000 * (*pst1 - *pst2);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WINDOWS
|
|
||||||
if (windows_hires_timers)
|
|
||||||
return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_msfreq;
|
|
||||||
else
|
|
||||||
return pst1->lores - pst2->lores;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Measure the elapsed time since timer creation/reset and return it
|
/* Measure the elapsed time since timer creation/reset and return it
|
||||||
to the caller. The value remains stored for further reads by
|
to the caller. The value remains stored for further reads by
|
||||||
ptimer_read.
|
ptimer_read.
|
||||||
@ -340,8 +415,8 @@ ptimer_measure (struct ptimer *wt)
|
|||||||
|
|
||||||
assert (wt->initialized != 0);
|
assert (wt->initialized != 0);
|
||||||
|
|
||||||
ptimer_sys_set (&now);
|
IMPL_measure (&now);
|
||||||
elapsed = wt->elapsed_pre_start + ptimer_diff (&now, &wt->start);
|
elapsed = wt->elapsed_pre_start + IMPL_diff (&now, &wt->start);
|
||||||
|
|
||||||
/* Ideally we'd just return the difference between NOW and
|
/* Ideally we'd just return the difference between NOW and
|
||||||
wt->start. However, the system timer can be set back, and we
|
wt->start. However, the system timer can be set back, and we
|
||||||
@ -356,8 +431,8 @@ ptimer_measure (struct ptimer *wt)
|
|||||||
elapsed time and increment all future calculations by that
|
elapsed time and increment all future calculations by that
|
||||||
amount.
|
amount.
|
||||||
|
|
||||||
This cannot happen with Windows and CLOCK_MONOTONIC timers, but
|
This cannot happen with Windows and POSIX monotonic/highres
|
||||||
the check is not expensive. */
|
timers, but the check is not expensive. */
|
||||||
|
|
||||||
if (elapsed < wt->elapsed_last)
|
if (elapsed < wt->elapsed_last)
|
||||||
{
|
{
|
||||||
@ -379,34 +454,12 @@ ptimer_read (const struct ptimer *wt)
|
|||||||
return wt->elapsed_last;
|
return wt->elapsed_last;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the assessed granularity of the timer implementation, in
|
/* Return the assessed resolution of the timer implementation, in
|
||||||
milliseconds. This is used by code that tries to substitute a
|
milliseconds. This is used by code that tries to substitute a
|
||||||
better value for timers that have returned zero. */
|
better value for timers that have returned zero. */
|
||||||
|
|
||||||
double
|
double
|
||||||
ptimer_granularity (void)
|
ptimer_resolution (void)
|
||||||
{
|
{
|
||||||
#ifdef PTIMER_POSIX
|
return IMPL_resolution ();
|
||||||
/* POSIX timers give us a way to measure granularity. */
|
|
||||||
assert (posix_resolution != 0);
|
|
||||||
return posix_resolution;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_GETTIMEOFDAY
|
|
||||||
/* Granularity of gettimeofday varies wildly between architectures.
|
|
||||||
However, it appears that on modern machines it tends to be better
|
|
||||||
than 1ms. Assume 100 usecs. */
|
|
||||||
return 0.1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_TIME
|
|
||||||
return 1000;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PTIMER_WINDOWS
|
|
||||||
if (windows_hires_timers)
|
|
||||||
return 1.0 / windows_hires_msfreq;
|
|
||||||
else
|
|
||||||
return 10; /* according to MSDN */
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ so, delete this exception statement from your version. */
|
|||||||
struct ptimer; /* forward declaration; all struct
|
struct ptimer; /* forward declaration; all struct
|
||||||
members are private */
|
members are private */
|
||||||
|
|
||||||
struct ptimer *ptimer_allocate PARAMS ((void));
|
|
||||||
struct ptimer *ptimer_new PARAMS ((void));
|
struct ptimer *ptimer_new PARAMS ((void));
|
||||||
void ptimer_destroy PARAMS ((struct ptimer *));
|
void ptimer_destroy PARAMS ((struct ptimer *));
|
||||||
|
|
||||||
@ -41,6 +40,6 @@ void ptimer_reset PARAMS ((struct ptimer *));
|
|||||||
double ptimer_measure PARAMS ((struct ptimer *));
|
double ptimer_measure PARAMS ((struct ptimer *));
|
||||||
double ptimer_read PARAMS ((const struct ptimer *));
|
double ptimer_read PARAMS ((const struct ptimer *));
|
||||||
|
|
||||||
double ptimer_granularity PARAMS ((void));
|
double ptimer_resolution PARAMS ((void));
|
||||||
|
|
||||||
#endif /* PTIMER_H */
|
#endif /* PTIMER_H */
|
||||||
|
@ -534,10 +534,10 @@ calc_rate (wgint bytes, double msecs, int *units)
|
|||||||
|
|
||||||
if (msecs == 0)
|
if (msecs == 0)
|
||||||
/* If elapsed time is exactly zero, it means we're under the
|
/* If elapsed time is exactly zero, it means we're under the
|
||||||
granularity of the timer. This can easily happen on systems
|
resolution of the timer. This can easily happen on systems
|
||||||
that use time() for the timer. Since the interval lies between
|
that use time() for the timer. Since the interval lies between
|
||||||
0 and the timer's granularity, assume half the granularity. */
|
0 and the timer's resolution, assume half the resolution. */
|
||||||
msecs = ptimer_granularity () / 2.0;
|
msecs = ptimer_resolution () / 2.0;
|
||||||
|
|
||||||
dlrate = 1000.0 * bytes / msecs;
|
dlrate = 1000.0 * bytes / msecs;
|
||||||
if (dlrate < 1024.0)
|
if (dlrate < 1024.0)
|
||||||
|
Loading…
Reference in New Issue
Block a user