limit-rate revisited

Tweaks around handling of --limit-rate:

* tracing: trace outstanding timeouts by name
* multi: do not mark transfer as dirty that have
  an EXPIRE_TOOFAST set
* multi: have one static function to asses speed limits
* multi: when setting EXPIRE_TOOFAST remove the transfers
  from the dirty set
* progress: rename vars and comment on how speed limit
  timeouts are calculated, for clarity
* transfer: when speed limiting, exit the receive loop
  after a quarter of the limit has been received, not
  on the first chunk received.
* cf-ip-happy.c: clear EXPIRE_HAPPY_EYEBALLS on connect
* scorecard: add --limit-rate parameter to test with
  speed limits in effect
This commit is contained in:
Stefan Eissing 2025-09-02 15:16:21 +02:00
parent ad42850b23
commit c5fccfffc6
No known key found for this signature in database
10 changed files with 218 additions and 120 deletions

View file

@ -281,41 +281,40 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
* to wait to get back under the speed limit.
*/
timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d,
curl_off_t speed_limit,
curl_off_t bytes_per_sec,
struct curltime now)
{
curl_off_t size = d->cur_size - d->limit.start_size;
timediff_t minimum;
timediff_t actual;
curl_off_t bytes = d->cur_size - d->limit.start_size;
timediff_t should_ms;
timediff_t took_ms;
if(!speed_limit || !size)
/* no limit or we did not get to any bytes yet */
if(!bytes_per_sec || !bytes)
return 0;
/*
* 'minimum' is the number of milliseconds 'size' should take to download to
* stay below 'limit'.
*/
if(size < CURL_OFF_T_MAX/1000)
minimum = (timediff_t) (1000 * size / speed_limit);
/* The time it took us to have `bytes` */
took_ms = curlx_timediff_ceil(now, d->limit.start);
/* The time it *should* have taken us to have `bytes`
* when obeying the bytes_per_sec speed_limit. */
if(bytes < CURL_OFF_T_MAX/1000) {
/* (1000 * bytes / (bytes / sec)) = 1000 * sec = ms */
should_ms = (timediff_t) (1000 * bytes / bytes_per_sec);
}
else {
minimum = (timediff_t) (size / speed_limit);
if(minimum < TIMEDIFF_T_MAX/1000)
minimum *= 1000;
/* very large `bytes`, first calc the seconds it should have taken.
* if that is small enough, convert to milliseconds. */
should_ms = (timediff_t) (bytes / bytes_per_sec);
if(should_ms < TIMEDIFF_T_MAX/1000)
should_ms *= 1000;
else
minimum = TIMEDIFF_T_MAX;
should_ms = TIMEDIFF_T_MAX;
}
/*
* 'actual' is the time in milliseconds it took to actually download the
* last 'size' bytes.
*/
actual = curlx_timediff_ceil(now, d->limit.start);
if(actual < minimum) {
/* if it downloaded the data faster than the limit, make it wait the
difference */
return minimum - actual;
if(took_ms < should_ms) {
/* when gotten to `bytes` too fast, wait the difference */
return should_ms - took_ms;
}
return 0;
}