aboutsummaryrefslogtreecommitdiff
path: root/lib/transfer.c
diff options
context:
space:
mode:
authorBen Greear <greearb@candelatech.com>2010-03-26 23:33:02 +0100
committerDaniel Stenberg <daniel@haxx.se>2010-03-26 23:33:02 +0100
commit7de44e0a428f88f88483076a19c173f004de9e46 (patch)
tree386c6a98daa87f2d7918f659fc7969df6b482c05 /lib/transfer.c
parent05de2cf18094ddfb461b70bd5e6af4b6098c408c (diff)
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.
Diffstat (limited to 'lib/transfer.c')
-rw-r--r--lib/transfer.c88
1 files changed, 83 insertions, 5 deletions
diff --git a/lib/transfer.c b/lib/transfer.c
index ad9499c99..2d504050c 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -1175,6 +1175,60 @@ int Curl_single_getsock(const struct connectdata *conn,
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()
@@ -1197,6 +1251,8 @@ Transfer(struct connectdata *conn)
bool done=FALSE;
bool first=TRUE;
int timeout_ms;
+ int buffersize;
+ int totmp;
if((conn->sockfd == 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_write = conn->writesockfd;
int keepon = k->keepon;
+ timeout_ms = 1000;
if(conn->waitfor) {
/* 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;
}
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;
if(keepon & KEEP_SEND)
k->keepon |= KEEP_SEND_HOLD; /* hold it */
@@ -1239,6 +1306,16 @@ Transfer(struct connectdata *conn)
k->keepon &= ~KEEP_RECV_HOLD;
}
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;
if(keepon & KEEP_RECV)
k->keepon |= KEEP_RECV_HOLD; /* hold it */
@@ -1267,14 +1344,15 @@ Transfer(struct connectdata *conn)
timeout_ms = 0;
else {
if(data->set.timeout) {
- timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start);
- if(timeout_ms > 1000)
- timeout_ms = 1000;
- else if(timeout_ms < 0)
+ totmp = (int)(data->set.timeout - Curl_tvdiff(k->now, k->start));
+ if(totmp < 0)
return CURLE_OPERATION_TIMEDOUT;
}
else
- timeout_ms = 1000;
+ totmp = 1000;
+
+ if (totmp < timeout_ms)
+ timeout_ms = totmp;
}
switch (Curl_socket_ready(fd_read, fd_write, timeout_ms)) {