1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Adjust bandwidth limitation sleep for the error of previous sleeps.

Allow decimal numbers in bandwidth limit specification.
This commit is contained in:
hniksic 2003-09-20 21:05:12 -07:00
parent 0bc3dc073f
commit b8e416c6c7
4 changed files with 145 additions and 98 deletions

3
NEWS
View File

@ -52,7 +52,8 @@ as "//img.foo.com/foo.jpg".
values "yes" and "no" along with the traditional "on" and "off". values "yes" and "no" along with the traditional "on" and "off".
** It is now possible to specify decimal values for --timeout, --wait, ** It is now possible to specify decimal values for --timeout, --wait,
and --waitretry. For instance, `--wait=0.5' now works as expected. --waitretry, and --limit-rate. For instance, `--wait=0.5' now
works as expected, and so does --limit-rate=2.5k.
* Wget 1.8.2 is a bugfix release with no user-visible changes. * Wget 1.8.2 is a bugfix release with no user-visible changes.

View File

@ -1,3 +1,13 @@
2003-09-21 Hrvoje Niksic <hniksic@xemacs.org>
* init.c (simple_atof): New function.
(cmd_time): Use it.
(cmd_bytes): Accept things like "1.5k" and such. Use simple_atof
to parse decimals.
* retr.c (limit_bandwidth): Adjust each sleep by the error of the
previous one.
2003-09-21 Hrvoje Niksic <hniksic@xemacs.org> 2003-09-21 Hrvoje Niksic <hniksic@xemacs.org>
* main.c (main): Use setoptval() for setting the options. Use * main.c (main): Use setoptval() for setting the options. Use

View File

@ -839,64 +839,115 @@ cmd_directory_vector (const char *com, const char *val, void *closure)
return 1; return 1;
} }
/* Set the value stored in VAL to CLOSURE (which should point to a /* Poor man's atof: handles only <digits>.<digits>. Returns 1 on
long int), allowing several postfixes, with the following syntax success, 0 on failure. In case of success, stores its result to
(regexp): *DEST. */
[0-9]+ -> bytes static int
[0-9]+[kK] -> bytes * 1024 simple_atof (const char *beg, const char *end, double *dest)
[0-9]+[mM] -> bytes * 1024 * 1024 {
inf -> 0 double result = 0;
int seen_dot = 0;
int seen_digit = 0;
double divider = 1;
const char *p = beg;
while (p < end)
{
char ch = *p++;
if (ISDIGIT (ch))
{
if (!seen_dot)
result = (10 * result) + (ch - '0');
else
result += (ch - '0') / (divider *= 10);
seen_digit = 1;
}
else if (ch == '.')
{
if (!seen_dot)
seen_dot = 1;
else
return 0;
}
}
if (!seen_digit)
return 0;
*dest = result;
return 1;
}
/* Parse VAL as a number and set its value to CLOSURE (which should
point to a long int).
By default, the value is assumed to be in bytes. If "K", "M", or
"G" are appended, the value is multiplied with 1<<10, 1<<20, or
1<<30, respectively. Floating point values are allowed and are
cast to integer before use. The idea is to be able to use things
like 1.5k instead of "1536".
The string "inf" is returned as 0.
In case of error, 0 is returned and memory pointed to by CLOSURE
remains unmodified. */
Anything else is flagged as incorrect, and CLOSURE is unchanged. */
static int static int
cmd_bytes (const char *com, const char *val, void *closure) cmd_bytes (const char *com, const char *val, void *closure)
{ {
long result; long mult;
long *out = (long *)closure; double number;
const char *p; const char *end = val + strlen (val);
result = 0;
p = val;
/* Check for "inf". */ /* Check for "inf". */
if (p[0] == 'i' && p[1] == 'n' && p[2] == 'f' && p[3] == '\0') if (0 == strcmp (val, "inf"))
{ {
*out = 0; *(long *)closure = 0;
return 1; return 1;
} }
/* Search for digits and construct result. */
for (; *p && ISDIGIT (*p); p++) /* Strip trailing whitespace. */
result = (10 * result) + (*p - '0'); while (val < end && ISSPACE (end[-1]))
/* If no digits were found, or more than one character is following --end;
them, bail out. */
if (p == val || (*p != '\0' && *(p + 1) != '\0')) if (val == end)
{ {
printf (_("%s: Invalid specification `%s'\n"), com, val); err:
fprintf (stderr, _("%s: Invalid byte value `%s'\n"), com, val);
return 0; return 0;
} }
/* Search for a designator. */
switch (TOLOWER (*p)) switch (TOLOWER (end[-1]))
{ {
case '\0':
/* None */
break;
case 'k': case 'k':
/* Kilobytes */ --end, mult = 1L<<10;
result *= 1024;
break; break;
case 'm': case 'm':
/* Megabytes */ --end, mult = 1L<<20;
result *= (long)1024 * 1024;
break; break;
case 'g': case 'g':
/* Gigabytes */ --end, mult = 1L<<30;
result *= (long)1024 * 1024 * 1024;
break; break;
default: default:
printf (_("%s: Invalid specification `%s'\n"), com, val); /* Not a recognized suffix: assume it belongs to the number.
return 0; (If not, atof simple_atof will raise an error.) */
mult = 1;
} }
*out = result;
/* Skip leading and trailing whitespace. */
while (val < end && ISSPACE (*val))
++val;
while (val < end && ISSPACE (end[-1]))
--end;
if (val == end)
goto err;
if (!simple_atof (val, end, &number))
goto err;
*(long *)closure = (long)(number * mult);
return 1; return 1;
} }
@ -907,14 +958,11 @@ cmd_bytes (const char *com, const char *val, void *closure)
static int static int
cmd_time (const char *com, const char *val, void *closure) cmd_time (const char *com, const char *val, void *closure)
{ {
double result, mult, divider; double number, mult;
int seen_dot, seen_digit;
const char *p;
const char *end = val + strlen (val); const char *end = val + strlen (val);
/* Skip trailing whitespace. */ /* Strip trailing whitespace. */
while (end > val && ISSPACE (end[-1])) while (val < end && ISSPACE (end[-1]))
--end; --end;
if (val == end) if (val == end)
@ -936,54 +984,29 @@ cmd_time (const char *com, const char *val, void *closure)
--end, mult = 3600; /* hours */ --end, mult = 3600; /* hours */
break; break;
case 'd': case 'd':
--end, mult = 86400; /* days */ --end, mult = 86400.0; /* days */
break; break;
case 'w': case 'w':
--end, mult = 604800; /* weeks */ --end, mult = 604800.0; /* weeks */
break; break;
default: default:
/* Not a recognized suffix: treat it as part of number, and /* Not a recognized suffix: assume it belongs to the number.
assume seconds. */ (If not, atof simple_atof will raise an error.) */
mult = 1; mult = 1;
} }
/* Skip leading and trailing whitespace. */ /* Skip leading and trailing whitespace. */
while (val < end && ISSPACE (*val)) while (val < end && ISSPACE (*val))
++val; ++val;
while (val > end && ISSPACE (end[-1])) while (val < end && ISSPACE (end[-1]))
--end; --end;
if (val == end) if (val == end)
goto err; goto err;
/* Poor man's strtod: */ if (!simple_atof (val, end, &number))
result = 0; goto err;
seen_dot = seen_digit = 0;
divider = 1;
p = val; *(double *)closure = number * mult;
while (p < end)
{
char ch = *p++;
if (ISDIGIT (ch))
{
if (!seen_dot)
result = (10 * result) + (ch - '0');
else
result += (ch - '0') / (divider *= 10);
seen_digit = 1;
}
else if (ch == '.')
{
if (!seen_dot)
seen_dot = 1;
else
goto err;
}
}
if (!seen_digit)
goto err;
result *= mult;
*(double *)closure = result;
return 1; return 1;
} }

View File

@ -67,15 +67,16 @@ int global_download_count;
static struct { static struct {
long bytes; long chunk_bytes;
double dltime; double chunk_start;
double sleep_adjust;
} limit_data; } limit_data;
static void static void
limit_bandwidth_reset (void) limit_bandwidth_reset (void)
{ {
limit_data.bytes = 0; limit_data.chunk_bytes = 0;
limit_data.dltime = 0; limit_data.chunk_start = 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.
@ -83,30 +84,48 @@ limit_bandwidth_reset (void)
is the number of milliseconds it took to receive them. */ is the number of milliseconds it took to receive them. */
static void static void
limit_bandwidth (long bytes, double delta) limit_bandwidth (long bytes, double *dltime, struct wget_timer *timer)
{ {
double delta_t = *dltime - limit_data.chunk_start;
double expected; double expected;
limit_data.bytes += bytes; limit_data.chunk_bytes += bytes;
limit_data.dltime += delta;
expected = 1000.0 * limit_data.bytes / opt.limit_rate; /* Calculate the amount of time we expect downloading the chunk
should take. If in reality it took less time, sleep to
compensate for the difference. */
expected = 1000.0 * limit_data.chunk_bytes / opt.limit_rate;
if (expected > limit_data.dltime) if (expected > delta_t)
{ {
double slp = expected - limit_data.dltime; double slp = expected - delta_t + limit_data.sleep_adjust;
double t0, t1;
if (slp < 200) if (slp < 200)
{ {
DEBUGP (("deferring a %.2f ms sleep (%ld/%.2f).\n", DEBUGP (("deferring a %.2f ms sleep (%ld/%.2f).\n",
slp, limit_data.bytes, limit_data.dltime)); slp, limit_data.chunk_bytes, delta_t));
return; return;
} }
DEBUGP (("sleeping %.2f ms\n", slp)); DEBUGP (("\nsleeping %.2f ms for %ld bytes, adjust %.2f ms\n",
slp, limit_data.chunk_bytes, limit_data.sleep_adjust));
t0 = *dltime;
usleep ((unsigned long) (1000 * slp)); usleep ((unsigned long) (1000 * slp));
t1 = wtimer_elapsed (timer);
/* Due to scheduling, we probably slept slightly longer (or
shorter) than desired. Calculate the difference between the
desired and the actual sleep, and adjust the next sleep by
that amount. */
limit_data.sleep_adjust = slp - (t1 - t0);
/* Since we've called wtimer_elapsed, we might as well update
the caller's dltime. */
*dltime = t1;
} }
limit_data.bytes = 0; limit_data.chunk_bytes = 0;
limit_data.dltime = 0; limit_data.chunk_start = *dltime;
} }
#define MIN(i, j) ((i) <= (j) ? (i) : (j)) #define MIN(i, j) ((i) <= (j) ? (i) : (j))
@ -143,7 +162,7 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
void *progress = NULL; void *progress = NULL;
struct wget_timer *timer = wtimer_allocate (); struct wget_timer *timer = wtimer_allocate ();
double dltime = 0, last_dltime = 0; double dltime = 0;
*len = restval; *len = restval;
@ -210,15 +229,9 @@ get_contents (int fd, FILE *fp, long *len, long restval, long expected,
goto out; goto out;
} }
/* If bandwidth is not limited, one call to wtimer_elapsed is
sufficient. */
dltime = wtimer_elapsed (timer); dltime = wtimer_elapsed (timer);
if (opt.limit_rate) if (opt.limit_rate)
{ limit_bandwidth (res, &dltime, timer);
limit_bandwidth (res, dltime - last_dltime);
dltime = wtimer_elapsed (timer);
last_dltime = dltime;
}
if (progress) if (progress)
progress_update (progress, res, dltime); progress_update (progress, res, dltime);