Files
curl/lib/ratelimit.h
Stefan Eissing 1a57302d1a ratelimit: download finetune
When a download size is known and rate limiting is in effect, adjust the
duration of each measurement step and its rate for maximum precision.

Since it is unpredictable how long the last bytes of a download will
take, download speed can be thrown off if the "last bytes" are a
significant amount of the total download. Make the "last bytes" small in
comparision to the rest and "stretch" the rate limit intervals to
accommodate the difference.

Fix ngtcp2 receive data acknowldgements to be based on a local window
size tracking. This allows window updates controlled by rate limits.

Fix ratelimit wait time calculation to accomodate negative tokens.

h3 rate limit, update timeers

Make download rate limits work correctly in ngtcp2. Fix multi handling
of rate limits to set a timer for when limits will update again.

Without running the transfer on limit updates, protocols like h2/h3 may
stall if the server does not send due to stream windows being too small.

scorecard: measure download speedlimits

When running scorecard with --limit-rate=n, show the reported download
speed averages plus percentage deviation from the limit.

Closes #20228
2026-01-16 16:42:31 +01:00

107 lines
4.5 KiB
C

#ifndef HEADER_CURL_RLIMIT_H
#define HEADER_CURL_RLIMIT_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curlx/timeval.h"
struct Curl_easy;
/* This is a rate limiter that provides "tokens" to be consumed
* per second. In the literature, this is referred to as a
* "token bucket" (https://en.wikipedia.org/wiki/Token_bucket).
* Example:
* A rate limit of 1 megabyte per second.
* - initially 1 million tokens are available.
* - these are drained in the first second.
* - checking available tokens before the 2nd second will return 0.
* - at/after the 2nd second, 1 million tokens are available again.
* - nothing happens for a second, the 1 million tokens would grow
* to 2 million, however the burst limit caps those at 1.5 million.
* Thus:
* - setting "burst" to CURL_OFF_T_MAX would average tokens over the
* complete lifetime. E.g. for a download, at the *end* of it, the
* average rate from start to finish would be the rate limit.
* - setting "burst" to the same value as "rate" would make a
* download always try to stay *at/below* the rate and slow times will
* not generate extra tokens.
*
* A rate limit can be blocked, causing the available tokens to become
* always 0 until unblocked. After unblocking, the rate limiting starts
* again with no history of the past.
*
* Finally, a rate limiter with rate 0 will always have CURL_OFF_T_MAX
* tokens available, unless blocked.
*/
struct Curl_rlimit {
int64_t rate_per_step; /* rate tokens generated per step us */
int64_t burst_per_step; /* burst rate of tokens per step us */
timediff_t step_us; /* microseconds between token increases */
int64_t tokens; /* tokens available in the next second */
timediff_t spare_us; /* microseconds unaffecting tokens */
struct curltime ts; /* time of the last update */
BIT(blocked); /* blocking sets available tokens to 0 */
};
void Curl_rlimit_init(struct Curl_rlimit *r,
int64_t rate_per_sec,
int64_t burst_per_sec,
const struct curltime *pts);
/* Start ratelimiting with the given timestamp. Resets available tokens.
* `total_tokens` is either -1 or the number of total tokens expected
* to be consumed. */
void Curl_rlimit_start(struct Curl_rlimit *r, const struct curltime *pts,
int64_t total_tokens);
/* How many milliseconds to wait until token are available again. */
timediff_t Curl_rlimit_wait_ms(struct Curl_rlimit *r,
const struct curltime *pts);
/* When the rate limit will update its tokens again */
timediff_t Curl_rlimit_next_step_ms(struct Curl_rlimit *r,
const struct curltime *pts);
/* Return if rate limiting of tokens is active */
bool Curl_rlimit_active(struct Curl_rlimit *r);
bool Curl_rlimit_is_blocked(struct Curl_rlimit *r);
int64_t Curl_rlimit_per_step(struct Curl_rlimit *r);
/* Return how many tokens are available to spend, may be negative */
int64_t Curl_rlimit_avail(struct Curl_rlimit *r,
const struct curltime *pts);
/* Drain tokens from the ratelimit, give an estimate of how many tokens
* remain to be drained in the future (-1 for unknown). */
void Curl_rlimit_drain(struct Curl_rlimit *r,
size_t tokens,
const struct curltime *pts);
/* Block/unblock ratelimiting. A blocked ratelimit has 0 tokens available. */
void Curl_rlimit_block(struct Curl_rlimit *r,
bool activate,
const struct curltime *pts);
#endif /* HEADER_CURL_RLIMIT_H */