[svn] Make timers measure seconds directly, not milliseconds.

This commit is contained in:
hniksic 2005-07-06 09:35:42 -07:00
parent bfbd0d35e9
commit 3d5863424b
6 changed files with 88 additions and 85 deletions

View File

@ -1,3 +1,8 @@
2005-07-06 Hrvoje Niksic <hniksic@xemacs.org>
* ptimer.c: Measure time in seconds rather than milliseconds.
Adjusted all callers.
2005-07-06 Hrvoje Niksic <hniksic@xemacs.org> 2005-07-06 Hrvoje Niksic <hniksic@xemacs.org>
* http.c (gethttp): When freeing MESSAGE, take into account that * http.c (gethttp): When freeing MESSAGE, take into account that

View File

@ -166,7 +166,7 @@ convert_all_links (void)
free_urlpos (urls); free_urlpos (urls);
} }
secs = ptimer_measure (timer) / 1000; secs = ptimer_measure (timer);
ptimer_destroy (timer); ptimer_destroy (timer);
logprintf (LOG_VERBOSE, _("Converted %d files in %s seconds.\n"), logprintf (LOG_VERBOSE, _("Converted %d files in %s seconds.\n"),
file_count, print_decimal (secs)); file_count, print_decimal (secs));

View File

@ -974,7 +974,7 @@ Can't timestamp and not clobber old files at the same time.\n"));
time_str (NULL), time_str (NULL),
opt.numurls, opt.numurls,
human_readable (total_downloaded_bytes), human_readable (total_downloaded_bytes),
secs_to_human_time (total_download_time / 1000), secs_to_human_time (total_download_time),
retr_rate (total_downloaded_bytes, total_download_time)); retr_rate (total_downloaded_bytes, total_download_time));
/* Print quota warning, if exceeded. */ /* Print quota warning, if exceeded. */
if (opt.quota && total_downloaded_bytes > opt.quota) if (opt.quota && total_downloaded_bytes > opt.quota)

View File

@ -175,7 +175,7 @@ progress_interactive_p (void *progress)
} }
/* Inform the progress gauge of newly received bytes. DLTIME is the /* Inform the progress gauge of newly received bytes. DLTIME is the
time in milliseconds since the beginning of the download. */ time since the beginning of the download. */
void void
progress_update (void *progress, wgint howmuch, double dltime) progress_update (void *progress, wgint howmuch, double dltime)
@ -320,20 +320,18 @@ print_row_stats (struct dot_progress *dp, double dltime, bool last)
wgint bytes_remaining = dp->total_length - bytes_displayed; wgint bytes_remaining = dp->total_length - bytes_displayed;
/* The quantity downloaded in this download run. */ /* The quantity downloaded in this download run. */
wgint bytes_sofar = bytes_displayed - dp->initial_length; wgint bytes_sofar = bytes_displayed - dp->initial_length;
double secs_sofar = dltime / 1000; int eta = (int) (dltime * bytes_remaining / bytes_sofar + 0.5);
int eta = (int) (secs_sofar * bytes_remaining / bytes_sofar + 0.5);
logprintf (LOG_VERBOSE, " %s", eta_to_human_short (eta, true)); logprintf (LOG_VERBOSE, " %s", eta_to_human_short (eta, true));
} }
} }
else else
{ {
/* When done, print the total download time */ /* When done, print the total download time */
double secs = dltime / 1000; if (dltime >= 10)
if (secs >= 10)
logprintf (LOG_VERBOSE, "=%s", logprintf (LOG_VERBOSE, "=%s",
eta_to_human_short ((int) (secs + 0.5), true)); eta_to_human_short ((int) (dltime + 0.5), true));
else else
logprintf (LOG_VERBOSE, "=%ss", print_decimal (secs)); logprintf (LOG_VERBOSE, "=%ss", print_decimal (dltime));
} }
} }
@ -478,12 +476,12 @@ static volatile sig_atomic_t received_sigwinch;
sample is at least 150ms long, which means that, over the course of sample is at least 150ms long, which means that, over the course of
20 samples, "current" download speed spans at least 3s into the 20 samples, "current" download speed spans at least 3s into the
past. */ past. */
#define DLSPEED_SAMPLE_MIN 150 #define DLSPEED_SAMPLE_MIN 0.15
/* The time after which the download starts to be considered /* The time after which the download starts to be considered
"stalled", i.e. the current bandwidth is not printed and the recent "stalled", i.e. the current bandwidth is not printed and the recent
download speeds are scratched. */ download speeds are scratched. */
#define STALL_START_TIME 5000 #define STALL_START_TIME 5
struct bar_progress { struct bar_progress {
wgint initial_length; /* how many bytes have been downloaded wgint initial_length; /* how many bytes have been downloaded
@ -513,12 +511,12 @@ struct bar_progress {
details. */ details. */
struct bar_progress_hist { struct bar_progress_hist {
int pos; int pos;
wgint times[DLSPEED_HISTORY_SIZE]; double times[DLSPEED_HISTORY_SIZE];
wgint bytes[DLSPEED_HISTORY_SIZE]; wgint bytes[DLSPEED_HISTORY_SIZE];
/* The sum of times and bytes respectively, maintained for /* The sum of times and bytes respectively, maintained for
efficiency. */ efficiency. */
wgint total_time; double total_time;
wgint total_bytes; wgint total_bytes;
} hist; } hist;
@ -618,7 +616,7 @@ bar_update (void *progress, wgint howmuch, double dltime)
received_sigwinch = 0; received_sigwinch = 0;
} }
if (dltime - bp->last_screen_update < 200 && !force_screen_update) if (dltime - bp->last_screen_update < 0.2 && !force_screen_update)
/* Don't update more often than five times per second. */ /* Don't update more often than five times per second. */
return; return;
@ -708,7 +706,7 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
value because the current bandwidth would start too small. value because the current bandwidth would start too small.
Start with an arbitrary (but more reasonable) time value and Start with an arbitrary (but more reasonable) time value and
let it level out. */ let it level out. */
recent_age = 1000; recent_age = 1;
} }
/* Store "recent" bytes and download time to history ring at the /* Store "recent" bytes and download time to history ring at the
@ -743,8 +741,14 @@ update_speed_ring (struct bar_progress *bp, wgint howmuch, double dltime)
sumt += hist->times[i]; sumt += hist->times[i];
sumb += hist->bytes[i]; sumb += hist->bytes[i];
} }
assert (sumt == hist->total_time);
assert (sumb == hist->total_bytes); assert (sumb == hist->total_bytes);
/* We can't use assert(sumt==hist->total_time) because some
precision is lost by adding and subtracting floating-point
numbers. But during a download this precision should not be
detectable, i.e. no larger than 1ns. */
double diff = sumt - hist->total_time;
if (diff < 0) diff = -diff;
assert (diff < 1e-9);
} }
#endif #endif
} }
@ -879,7 +883,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
move_to_end (p); move_to_end (p);
/* " 12.52K/s" */ /* " 12.52K/s" */
if (hist->total_time && hist->total_bytes) if (hist->total_time > 0 && hist->total_bytes)
{ {
static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" }; static const char *short_units[] = { "B/s", "K/s", "M/s", "G/s" };
int units = 0; int units = 0;
@ -900,7 +904,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
/* " eta ..m ..s"; wait for three seconds before displaying the ETA. /* " eta ..m ..s"; wait for three seconds before displaying the ETA.
That's because the ETA value needs a while to become That's because the ETA value needs a while to become
reliable. */ reliable. */
if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3000) if (bp->total_length > 0 && bp->count > 0 && dl_total_time > 3)
{ {
int eta; int eta;
@ -909,7 +913,7 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
any value to the user. */ any value to the user. */
if (bp->total_length != size if (bp->total_length != size
&& bp->last_eta_value != 0 && bp->last_eta_value != 0
&& dl_total_time - bp->last_eta_time < 900) && dl_total_time - bp->last_eta_time < 0.9)
eta = bp->last_eta_value; eta = bp->last_eta_value;
else else
{ {
@ -919,9 +923,8 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
hist->total_time and bp->count with hist->total_bytes. hist->total_time and bp->count with hist->total_bytes.
I found that doing that results in a very jerky and I found that doing that results in a very jerky and
ultimately unreliable ETA. */ ultimately unreliable ETA. */
double time_sofar = (double) dl_total_time / 1000;
wgint bytes_remaining = bp->total_length - size; wgint bytes_remaining = bp->total_length - size;
eta = (int) (time_sofar * bytes_remaining / bp->count + 0.5); eta = (int) (dl_total_time * bytes_remaining / bp->count + 0.5);
bp->last_eta_value = eta; bp->last_eta_value = eta;
bp->last_eta_time = dl_total_time; bp->last_eta_time = dl_total_time;
} }
@ -939,15 +942,15 @@ create_image (struct bar_progress *bp, double dl_total_time, bool done)
else else
{ {
/* When the download is done, print the elapsed time. */ /* When the download is done, print the elapsed time. */
double secs = dl_total_time / 1000;
/* Note to translators: this should not take up more room than /* Note to translators: this should not take up more room than
available here. Abbreviate if necessary. */ available here. Abbreviate if necessary. */
strcpy (p, _(" in ")); strcpy (p, _(" in "));
move_to_end (p); /* not p+=6, think translations! */ move_to_end (p); /* not p+=6, think translations! */
if (secs >= 10) if (dl_total_time >= 10)
strcpy (p, eta_to_human_short ((int) (secs + 0.5), false)); strcpy (p, eta_to_human_short ((int) (dl_total_time + 0.5), false));
else else
sprintf (p, "%ss", print_decimal (secs)); sprintf (p, "%ss", print_decimal (dl_total_time));
move_to_end (p); move_to_end (p);
} }

View File

@ -39,16 +39,16 @@ so, delete this exception statement from your version. */
ptimer_destroy -- destroy the timer. ptimer_destroy -- destroy the timer.
ptimer_granularity -- returns the approximate granularity of the timers. ptimer_granularity -- returns the approximate granularity of the timers.
Timers measure time in milliseconds, but the timings they return Timers measure time in seconds, returning the timings as floating
are floating point numbers, so they can carry as much precision as point numbers, so they can carry as much precision as the
the underlying system timer supports. For example, to measure the underlying system timer supports. For example, to measure the time
time it takes to run a loop, you can use something like: it takes to run a loop, you can use something like:
ptimer *tmr = ptimer_new (); ptimer *tmr = ptimer_new ();
while (...) while (...)
... loop ... ... loop ...
double msecs = ptimer_measure (); double secs = ptimer_measure ();
printf ("The loop took %.2f ms\n", msecs); */ printf ("The loop took %.2fs\n", secs); */
#include <config.h> #include <config.h>
@ -108,8 +108,8 @@ typedef struct timespec ptimer_system_time;
CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise. */ CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise. */
static int posix_clock_id; static int posix_clock_id;
/* Resolution of the clock, in milliseconds. */ /* Resolution of the clock, initialized in posix_init. */
static double posix_millisec_resolution; static double posix_clock_resolution;
/* Decide which clock_id to use. */ /* Decide which clock_id to use. */
@ -148,11 +148,10 @@ posix_init (void)
if (clock_getres (clocks[i].id, &r) < 0) if (clock_getres (clocks[i].id, &r) < 0)
continue; /* clock_getres doesn't work for this clock */ continue; /* clock_getres doesn't work for this clock */
posix_clock_id = clocks[i].id; posix_clock_id = clocks[i].id;
posix_millisec_resolution = r.tv_sec * 1000.0 + r.tv_nsec / 1000000.0; posix_clock_resolution = (double) r.tv_sec + r.tv_nsec / 1e9;
/* Guard against broken clock_getres returning nonsensical /* Guard against nonsense returned by a broken clock_getres. */
values. */ if (posix_clock_resolution == 0)
if (posix_millisec_resolution == 0) posix_clock_resolution = 1e-3;
posix_millisec_resolution = 1;
break; break;
} }
if (i == countof (clocks)) if (i == countof (clocks))
@ -163,7 +162,7 @@ posix_init (void)
strerror (errno)); strerror (errno));
/* Use CLOCK_REALTIME, but invent a plausible resolution. */ /* Use CLOCK_REALTIME, but invent a plausible resolution. */
posix_clock_id = CLOCK_REALTIME; posix_clock_id = CLOCK_REALTIME;
posix_millisec_resolution = 1; posix_clock_resolution = 1e-3;
} }
} }
@ -176,14 +175,14 @@ posix_measure (ptimer_system_time *pst)
static inline double static inline double
posix_diff (ptimer_system_time *pst1, ptimer_system_time *pst2) posix_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
{ {
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0 return ((pst1->tv_sec - pst2->tv_sec)
+ (pst1->tv_nsec - pst2->tv_nsec) / 1000000.0); + (pst1->tv_nsec - pst2->tv_nsec) / 1e9);
} }
static inline double static inline double
posix_resolution (void) posix_resolution (void)
{ {
return posix_millisec_resolution; return posix_clock_resolution;
} }
#endif /* PTIMER_POSIX */ #endif /* PTIMER_POSIX */
@ -209,8 +208,8 @@ gettimeofday_measure (ptimer_system_time *pst)
static inline double static inline double
gettimeofday_diff (ptimer_system_time *pst1, ptimer_system_time *pst2) gettimeofday_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
{ {
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0 return ((pst1->tv_sec - pst2->tv_sec)
+ (pst1->tv_usec - pst2->tv_usec) / 1000.0); + (pst1->tv_usec - pst2->tv_usec) / 1e6);
} }
static inline double static inline double
@ -246,9 +245,9 @@ typedef union {
static bool windows_hires_timers; static bool windows_hires_timers;
/* Frequency of high-resolution timers -- number of updates per /* Frequency of high-resolution timers -- number of updates per
millisecond. Calculated the first time ptimer_new is called second. Calculated the first time ptimer_new is called provided
provided that high-resolution timers are available. */ that high-resolution timers are available. */
static double windows_hires_msfreq; static double windows_hires_freq;
static void static void
windows_init (void) windows_init (void)
@ -259,7 +258,7 @@ windows_init (void)
if (freq.QuadPart != 0) if (freq.QuadPart != 0)
{ {
windows_hires_timers = true; windows_hires_timers = true;
windows_hires_msfreq = (double) freq.QuadPart / 1000.0; windows_hires_freq = (double) freq.QuadPart;
} }
} }
@ -281,7 +280,7 @@ static inline double
windows_diff (ptimer_system_time *pst1, ptimer_system_time *pst2) windows_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
{ {
if (windows_hires_timers) if (windows_hires_timers)
return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_msfreq; return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_freq;
else else
return pst1->lores - pst2->lores; return pst1->lores - pst2->lores;
} }
@ -290,7 +289,7 @@ static double
windows_resolution (void) windows_resolution (void)
{ {
if (windows_hires_timers) if (windows_hires_timers)
return 1.0 / windows_hires_msfreq; return 1.0 / windows_hires_freq;
else else
return 10; /* according to MSDN */ return 10; /* according to MSDN */
} }
@ -303,8 +302,7 @@ struct ptimer {
time, yields elapsed time. */ time, yields elapsed time. */
ptimer_system_time start; ptimer_system_time start;
/* The most recent elapsed time, calculated by ptimer_measure(). /* The most recent elapsed time, calculated by ptimer_measure(). */
Measured in milliseconds. */
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
@ -341,8 +339,8 @@ ptimer_destroy (struct ptimer *pt)
} }
/* Reset timer PT. This establishes the starting point from which /* Reset timer PT. This establishes the starting point from which
ptimer_read() will return the number of elapsed milliseconds. ptimer_measure() will return the elapsed time in seconds. It is
It is allowed to reset a previously used timer. */ allowed to reset a previously used timer. */
void void
ptimer_reset (struct ptimer *pt) ptimer_reset (struct ptimer *pt)
@ -353,13 +351,10 @@ ptimer_reset (struct ptimer *pt)
pt->elapsed_pre_start = 0; pt->elapsed_pre_start = 0;
} }
/* Measure the elapsed time since timer creation/reset and return it /* Measure the elapsed time since timer creation/reset. This causes
to the caller. The value remains stored for further reads by the timer to internally call clock_gettime (or gettimeofday, etc.)
ptimer_read. to update its idea of current time. The time is returned, but is
also stored for later access through ptimer_read().
This function causes the timer to call gettimeofday (or time(),
etc.) to update its idea of current time. To get the elapsed
interval in milliseconds, use ptimer_read.
This function handles clock skew, i.e. time that moves backwards is This function handles clock skew, i.e. time that moves backwards is
ignored. */ ignored. */
@ -400,8 +395,9 @@ ptimer_measure (struct ptimer *pt)
return elapsed; return elapsed;
} }
/* Return the elapsed time in milliseconds between the last call to /* Return the most recent elapsed time measured with ptimer_measure.
ptimer_reset and the last call to ptimer_update. */ If ptimer_measure has not yet been called since the timer was
created or reset, this returns 0. */
double double
ptimer_read (const struct ptimer *pt) ptimer_read (const struct ptimer *pt)
@ -410,8 +406,8 @@ ptimer_read (const struct ptimer *pt)
} }
/* Return the assessed resolution 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 seconds. This is used by code that tries to substitute a better
better value for timers that have returned zero. */ value for timers that have returned zero. */
double double
ptimer_resolution (void) ptimer_resolution (void)

View File

@ -55,7 +55,7 @@ so, delete this exception statement from your version. */
/* Total size of downloaded files. Used to enforce quota. */ /* Total size of downloaded files. Used to enforce quota. */
SUM_SIZE_INT total_downloaded_bytes; SUM_SIZE_INT total_downloaded_bytes;
/* Total download time in milliseconds. */ /* Total download time in seconds. */
double total_download_time; double total_download_time;
/* If non-NULL, the stream to which output should be written. This /* If non-NULL, the stream to which output should be written. This
@ -75,9 +75,7 @@ static struct {
static void static void
limit_bandwidth_reset (void) limit_bandwidth_reset (void)
{ {
limit_data.chunk_bytes = 0; xzero (limit_data);
limit_data.chunk_start = 0;
limit_data.sleep_adjust = 0;
} }
/* Limit the bandwidth by pausing the download for an amount of time. /* Limit the bandwidth by pausing the download for an amount of time.
@ -95,25 +93,25 @@ limit_bandwidth (wgint bytes, struct ptimer *timer)
/* Calculate the amount of time we expect downloading the chunk /* Calculate the amount of time we expect downloading the chunk
should take. If in reality it took less time, sleep to should take. If in reality it took less time, sleep to
compensate for the difference. */ compensate for the difference. */
expected = 1000.0 * limit_data.chunk_bytes / opt.limit_rate; expected = (double) limit_data.chunk_bytes / opt.limit_rate;
if (expected > delta_t) if (expected > delta_t)
{ {
double slp = expected - delta_t + limit_data.sleep_adjust; double slp = expected - delta_t + limit_data.sleep_adjust;
double t0, t1; double t0, t1;
if (slp < 200) if (slp < 0.2)
{ {
DEBUGP (("deferring a %.2f ms sleep (%s/%.2f).\n", DEBUGP (("deferring a %.2f ms sleep (%s/%.2f).\n",
slp, number_to_static_string (limit_data.chunk_bytes), slp * 1000, number_to_static_string (limit_data.chunk_bytes),
delta_t)); delta_t));
return; return;
} }
DEBUGP (("\nsleeping %.2f ms for %s bytes, adjust %.2f ms\n", DEBUGP (("\nsleeping %.2f ms for %s bytes, adjust %.2f ms\n",
slp, number_to_static_string (limit_data.chunk_bytes), slp * 1000, number_to_static_string (limit_data.chunk_bytes),
limit_data.sleep_adjust)); limit_data.sleep_adjust));
t0 = ptimer_read (timer); t0 = ptimer_read (timer);
xsleep (slp / 1000); xsleep (slp);
t1 = ptimer_measure (timer); t1 = ptimer_measure (timer);
/* Due to scheduling, we probably slept slightly longer (or /* Due to scheduling, we probably slept slightly longer (or
@ -123,10 +121,10 @@ limit_bandwidth (wgint bytes, struct ptimer *timer)
limit_data.sleep_adjust = slp - (t1 - t0); limit_data.sleep_adjust = slp - (t1 - t0);
/* If sleep_adjust is very large, it's likely due to suspension /* If sleep_adjust is very large, it's likely due to suspension
and not clock inaccuracy. Don't enforce those. */ and not clock inaccuracy. Don't enforce those. */
if (limit_data.sleep_adjust > 500) if (limit_data.sleep_adjust > 0.5)
limit_data.sleep_adjust = 500; limit_data.sleep_adjust = 0.5;
else if (limit_data.sleep_adjust < -500) else if (limit_data.sleep_adjust < -0.5)
limit_data.sleep_adjust = -500; limit_data.sleep_adjust = -0.5;
} }
limit_data.chunk_bytes = 0; limit_data.chunk_bytes = 0;
@ -185,7 +183,7 @@ write_data (FILE *out, const char *buf, int bufsize, wgint *skip,
is incremented by the amount of data read from the network. If is incremented by the amount of data read from the network. If
QTYWRITTEN is non-NULL, the value it points to is incremented by QTYWRITTEN is non-NULL, the value it points to is incremented by
the amount of data written to disk. The time it took to download the amount of data written to disk. The time it took to download
the data (in milliseconds) is stored to ELAPSED. the data is stored to ELAPSED.
The function exits and returns the amount of data read. In case of The function exits and returns the amount of data read. In case of
error while reading data, -1 is returned. In case of error while error while reading data, -1 is returned. In case of error while
@ -267,7 +265,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
if (opt.read_timeout) if (opt.read_timeout)
{ {
double waittm; double waittm;
waittm = (ptimer_read (timer) - last_successful_read_tm) / 1000; waittm = ptimer_read (timer) - last_successful_read_tm;
if (waittm + tmout > opt.read_timeout) if (waittm + tmout > opt.read_timeout)
{ {
/* Don't let total idle time exceed read timeout. */ /* Don't let total idle time exceed read timeout. */
@ -540,22 +538,23 @@ retr_rate (wgint bytes, double msecs)
UNITS is zero for B/s, one for KB/s, two for MB/s, and three for UNITS is zero for B/s, one for KB/s, two for MB/s, and three for
GB/s. */ GB/s. */
double double
calc_rate (wgint bytes, double msecs, int *units) calc_rate (wgint bytes, double secs, int *units)
{ {
double dlrate; double dlrate;
assert (msecs >= 0); assert (secs >= 0);
assert (bytes >= 0); assert (bytes >= 0);
if (msecs == 0) if (secs == 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
resolution 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 resolution, assume half the resolution. */ 0 and the timer's resolution, assume half the resolution. */
msecs = ptimer_resolution () / 2.0; secs = ptimer_resolution () / 2.0;
dlrate = 1000.0 * bytes / msecs; dlrate = bytes / secs;
if (dlrate < 1024.0) if (dlrate < 1024.0)
*units = 0; *units = 0;
else if (dlrate < 1024.0 * 1024.0) else if (dlrate < 1024.0 * 1024.0)