mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
Make rate-limitation logic smoother
This gives a smoother rate limitation performance by using sub-second pauses and also taking the buffer sizes into account.
This commit is contained in:
parent
05de2cf180
commit
7de44e0a42
38
lib/tftp.c
38
lib/tftp.c
@ -267,7 +267,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
|
|||||||
state->retry_max=50;
|
state->retry_max=50;
|
||||||
|
|
||||||
/* Compute the re-ACK interval to suit the timeout */
|
/* Compute the re-ACK interval to suit the timeout */
|
||||||
state->retry_time = timeout/state->retry_max;
|
state->retry_time = (int)(timeout/state->retry_max);
|
||||||
if(state->retry_time<1)
|
if(state->retry_time<1)
|
||||||
state->retry_time=1;
|
state->retry_time=1;
|
||||||
|
|
||||||
@ -1177,36 +1177,6 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static long sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
|
|
||||||
int pkt_size)
|
|
||||||
{
|
|
||||||
curl_off_t min_sleep = 0;
|
|
||||||
curl_off_t rv = 0;
|
|
||||||
|
|
||||||
if (rate_bps == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (cur_rate_bps > (rate_bps + (rate_bps >> 10))) {
|
|
||||||
/* running too fast */
|
|
||||||
rate_bps -= rate_bps >> 6;
|
|
||||||
min_sleep = 1;
|
|
||||||
}
|
|
||||||
else if (cur_rate_bps < (rate_bps - (rate_bps >> 10))) {
|
|
||||||
/* running too slow */
|
|
||||||
rate_bps += rate_bps >> 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps);
|
|
||||||
|
|
||||||
if (rv < min_sleep)
|
|
||||||
rv = min_sleep;
|
|
||||||
|
|
||||||
if(rv > 0x7fffffff)
|
|
||||||
rv = 0x7fffffff;
|
|
||||||
|
|
||||||
return (long)rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************
|
/**********************************************************
|
||||||
*
|
*
|
||||||
@ -1239,7 +1209,7 @@ static CURLcode tftp_easy_statemach(struct connectdata *conn)
|
|||||||
if (data->set.max_send_speed &&
|
if (data->set.max_send_speed &&
|
||||||
(data->progress.ulspeed > data->set.max_send_speed)) {
|
(data->progress.ulspeed > data->set.max_send_speed)) {
|
||||||
fd_read = CURL_SOCKET_BAD;
|
fd_read = CURL_SOCKET_BAD;
|
||||||
timeout_ms = sleep_time(data->set.max_send_speed,
|
timeout_ms = Curl_sleep_time(data->set.max_send_speed,
|
||||||
data->progress.ulspeed, state->blksize);
|
data->progress.ulspeed, state->blksize);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1250,7 +1220,7 @@ static CURLcode tftp_easy_statemach(struct connectdata *conn)
|
|||||||
if (data->set.max_recv_speed &&
|
if (data->set.max_recv_speed &&
|
||||||
(data->progress.dlspeed > data->set.max_recv_speed)) {
|
(data->progress.dlspeed > data->set.max_recv_speed)) {
|
||||||
fd_read = CURL_SOCKET_BAD;
|
fd_read = CURL_SOCKET_BAD;
|
||||||
timeout_ms = sleep_time(data->set.max_recv_speed,
|
timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
|
||||||
data->progress.dlspeed, state->blksize);
|
data->progress.dlspeed, state->blksize);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1268,7 +1238,7 @@ static CURLcode tftp_easy_statemach(struct connectdata *conn)
|
|||||||
|
|
||||||
|
|
||||||
/* Wait until ready to read or timeout occurs */
|
/* Wait until ready to read or timeout occurs */
|
||||||
rc=Curl_socket_ready(fd_read, CURL_SOCKET_BAD, timeout_ms);
|
rc = Curl_socket_ready(fd_read, CURL_SOCKET_BAD, (int)(timeout_ms));
|
||||||
|
|
||||||
k->now = Curl_tvnow();
|
k->now = Curl_tvnow();
|
||||||
|
|
||||||
|
@ -1175,6 +1175,60 @@ int Curl_single_getsock(const struct connectdata *conn,
|
|||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine optimum sleep time based on configured rate, current rate,
|
||||||
|
* and packet size.
|
||||||
|
* Returns value in mili-seconds.
|
||||||
|
*
|
||||||
|
* The basic idea is to adjust the desired rate up/down in this method
|
||||||
|
* based on whether we are running too slow or too fast. Then, calculate
|
||||||
|
* how many miliseconds to wait for the next packet to achieve this new
|
||||||
|
* rate.
|
||||||
|
*/
|
||||||
|
long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
|
||||||
|
int pkt_size)
|
||||||
|
{
|
||||||
|
curl_off_t min_sleep = 0;
|
||||||
|
curl_off_t rv = 0;
|
||||||
|
|
||||||
|
if (rate_bps == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* If running faster than about .1% of the desired speed, slow
|
||||||
|
* us down a bit. Use shift instead of division as the 0.1%
|
||||||
|
* cutoff is arbitrary anyway.
|
||||||
|
*/
|
||||||
|
if (cur_rate_bps > (rate_bps + (rate_bps >> 10))) {
|
||||||
|
/* running too fast, decrease target rate by 1/64th of rate */
|
||||||
|
rate_bps -= rate_bps >> 6;
|
||||||
|
min_sleep = 1;
|
||||||
|
}
|
||||||
|
else if (cur_rate_bps < (rate_bps - (rate_bps >> 10))) {
|
||||||
|
/* running too slow, increase target rate by 1/64th of rate */
|
||||||
|
rate_bps += rate_bps >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine number of miliseconds to wait until we do
|
||||||
|
* the next packet at the adjusted rate. We should wait
|
||||||
|
* longer when using larger packets, for instance.
|
||||||
|
*/
|
||||||
|
rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps);
|
||||||
|
|
||||||
|
/* Catch rounding errors and always slow down at least 1ms if
|
||||||
|
* we are running too fast.
|
||||||
|
*/
|
||||||
|
if (rv < min_sleep)
|
||||||
|
rv = min_sleep;
|
||||||
|
|
||||||
|
/* Bound value to fit in 'long' on 32-bit platform. That's
|
||||||
|
* plenty long enough anyway!
|
||||||
|
*/
|
||||||
|
if(rv > 0x7fffffff)
|
||||||
|
rv = 0x7fffffff;
|
||||||
|
|
||||||
|
return (long)rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transfer()
|
* Transfer()
|
||||||
@ -1197,6 +1251,8 @@ Transfer(struct connectdata *conn)
|
|||||||
bool done=FALSE;
|
bool done=FALSE;
|
||||||
bool first=TRUE;
|
bool first=TRUE;
|
||||||
int timeout_ms;
|
int timeout_ms;
|
||||||
|
int buffersize;
|
||||||
|
int totmp;
|
||||||
|
|
||||||
if((conn->sockfd == CURL_SOCKET_BAD) &&
|
if((conn->sockfd == CURL_SOCKET_BAD) &&
|
||||||
(conn->writesockfd == CURL_SOCKET_BAD))
|
(conn->writesockfd == CURL_SOCKET_BAD))
|
||||||
@ -1211,6 +1267,7 @@ Transfer(struct connectdata *conn)
|
|||||||
curl_socket_t fd_read = conn->sockfd;
|
curl_socket_t fd_read = conn->sockfd;
|
||||||
curl_socket_t fd_write = conn->writesockfd;
|
curl_socket_t fd_write = conn->writesockfd;
|
||||||
int keepon = k->keepon;
|
int keepon = k->keepon;
|
||||||
|
timeout_ms = 1000;
|
||||||
|
|
||||||
if(conn->waitfor) {
|
if(conn->waitfor) {
|
||||||
/* if waitfor is set, get the RECV and SEND bits from that but keep the
|
/* if waitfor is set, get the RECV and SEND bits from that but keep the
|
||||||
@ -1228,6 +1285,16 @@ Transfer(struct connectdata *conn)
|
|||||||
k->keepon &= ~KEEP_SEND_HOLD;
|
k->keepon &= ~KEEP_SEND_HOLD;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (data->set.upload && data->set.max_send_speed &&
|
||||||
|
(data->progress.ulspeed > data->set.max_send_speed) ) {
|
||||||
|
/* calculate upload rate-limitation timeout. */
|
||||||
|
buffersize = (int)(data->set.buffer_size ?
|
||||||
|
data->set.buffer_size : BUFSIZE);
|
||||||
|
totmp = (int)Curl_sleep_time(data->set.max_send_speed,
|
||||||
|
data->progress.ulspeed, buffersize);
|
||||||
|
if (totmp < timeout_ms)
|
||||||
|
timeout_ms = totmp;
|
||||||
|
}
|
||||||
fd_write = CURL_SOCKET_BAD;
|
fd_write = CURL_SOCKET_BAD;
|
||||||
if(keepon & KEEP_SEND)
|
if(keepon & KEEP_SEND)
|
||||||
k->keepon |= KEEP_SEND_HOLD; /* hold it */
|
k->keepon |= KEEP_SEND_HOLD; /* hold it */
|
||||||
@ -1239,6 +1306,16 @@ Transfer(struct connectdata *conn)
|
|||||||
k->keepon &= ~KEEP_RECV_HOLD;
|
k->keepon &= ~KEEP_RECV_HOLD;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if ((!data->set.upload) && data->set.max_recv_speed &&
|
||||||
|
(data->progress.dlspeed > data->set.max_recv_speed)) {
|
||||||
|
/* Calculate download rate-limitation timeout. */
|
||||||
|
buffersize = (int)(data->set.buffer_size ?
|
||||||
|
data->set.buffer_size : BUFSIZE);
|
||||||
|
totmp = (int)Curl_sleep_time(data->set.max_recv_speed,
|
||||||
|
data->progress.dlspeed, buffersize);
|
||||||
|
if (totmp < timeout_ms)
|
||||||
|
timeout_ms = totmp;
|
||||||
|
}
|
||||||
fd_read = CURL_SOCKET_BAD;
|
fd_read = CURL_SOCKET_BAD;
|
||||||
if(keepon & KEEP_RECV)
|
if(keepon & KEEP_RECV)
|
||||||
k->keepon |= KEEP_RECV_HOLD; /* hold it */
|
k->keepon |= KEEP_RECV_HOLD; /* hold it */
|
||||||
@ -1267,14 +1344,15 @@ Transfer(struct connectdata *conn)
|
|||||||
timeout_ms = 0;
|
timeout_ms = 0;
|
||||||
else {
|
else {
|
||||||
if(data->set.timeout) {
|
if(data->set.timeout) {
|
||||||
timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start);
|
totmp = (int)(data->set.timeout - Curl_tvdiff(k->now, k->start));
|
||||||
if(timeout_ms > 1000)
|
if(totmp < 0)
|
||||||
timeout_ms = 1000;
|
|
||||||
else if(timeout_ms < 0)
|
|
||||||
return CURLE_OPERATION_TIMEDOUT;
|
return CURLE_OPERATION_TIMEDOUT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
timeout_ms = 1000;
|
totmp = 1000;
|
||||||
|
|
||||||
|
if (totmp < timeout_ms)
|
||||||
|
timeout_ms = totmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Curl_socket_ready(fd_read, fd_write, timeout_ms)) {
|
switch (Curl_socket_ready(fd_read, fd_write, timeout_ms)) {
|
||||||
|
@ -60,4 +60,8 @@ Curl_setup_transfer (struct connectdata *data,
|
|||||||
-1 disables */
|
-1 disables */
|
||||||
curl_off_t *writecountp /* return number of bytes written */
|
curl_off_t *writecountp /* return number of bytes written */
|
||||||
);
|
);
|
||||||
|
|
||||||
|
long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
|
||||||
|
int pkt_size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user