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:
parent
0bc3dc073f
commit
b8e416c6c7
3
NEWS
3
NEWS
@ -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.
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
173
src/init.c
173
src/init.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
57
src/retr.c
57
src/retr.c
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user