From 75a45f501ef185c9a077d8d6e517981545704e12 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sun, 5 May 2013 21:06:13 +0200 Subject: [PATCH] Moved a part of AIPerService::wantsMoreHTTPRequestsFor to a new function. The new function is AIPerService::checkBandwidthUsage. No functional changes were made. --- indra/llmessage/aicurlperservice.h | 2 + indra/llmessage/aicurlthread.cpp | 123 +++++++++++++++-------------- 2 files changed, 67 insertions(+), 58 deletions(-) diff --git a/indra/llmessage/aicurlperservice.h b/indra/llmessage/aicurlperservice.h index 00647e517..61afd2cc7 100644 --- a/indra/llmessage/aicurlperservice.h +++ b/indra/llmessage/aicurlperservice.h @@ -172,6 +172,8 @@ class AIPerService { // Should return false if the maximum allowed HTTP bandwidth is reached, or when // the latency between request and actual delivery becomes too large. static bool wantsMoreHTTPRequestsFor(AIPerServicePtr const& per_service); + // Return true if too much bandwidth is being used. + static bool checkBandwidthUsage(U64 sTime_40ms, AIAverage* http_bandwidth_ptr); // Accessor for when curl_max_total_concurrent_connections changes. static LLAtomicS32& maxPipelinedRequests(void) { return sMaxPipelinedRequests; } diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index 55810fa50..2a0941db8 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -2673,68 +2673,15 @@ bool AIPerService::wantsMoreHTTPRequestsFor(AIPerServicePtr const& per_service) } if (reject) { - // Too many request for this host already. + // Too many request for this service already. return false; } - if (!sNoHTTPBandwidthThrottling) + // Throttle on bandwidth usage. + if (checkBandwidthUsage(sTime_40ms, http_bandwidth_ptr)) { - // Throttle on bandwidth usage. - - // Truncate the sums to the last second, and get their value. - size_t const max_bandwidth = AIPerService::getHTTPThrottleBandwidth125(); - size_t const total_bandwidth = BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms); // Bytes received in the past second. - size_t const service_bandwidth = http_bandwidth_ptr->truncateData(sTime_40ms); // Idem for just this service. - if (sTime_40ms > sLastTime_ThrottleFractionAverage_add) - { - sThrottleFractionAverage.addData(sThrottleFraction, sTime_40ms); - // Only add sThrottleFraction once every 40 ms at most. - // It's ok to ignore other values in the same 40 ms because the value only changes on the scale of 1 second. - sLastTime_ThrottleFractionAverage_add = sTime_40ms; - } - double fraction_avg = sThrottleFractionAverage.getAverage(1024.0); // sThrottleFraction averaged over the past second, or 1024 if there is no data. - - // Adjust sThrottleFraction based on total bandwidth usage. - if (total_bandwidth == 0) - sThrottleFraction = 1024; - else - { - // This is the main formula. It can be made plausible by assuming - // an equilibrium where total_bandwidth == max_bandwidth and - // thus sThrottleFraction == fraction_avg for more than a second. - // - // Then, more bandwidth is being used (for example because another - // service starts downloading). Assuming that all services that use - // a significant portion of the bandwidth, the new service included, - // must be throttled (all using the same bandwidth; note that the - // new service is immediately throttled at the same value), then - // the limit should be reduced linear with the fraction: - // max_bandwidth / total_bandwidth. - // - // For example, let max_bandwidth be 1. Let there be two throttled - // services, each using 0.5 (fraction_avg = 1024/2). Let the new - // service use what it can: also 0.5 - then without reduction the - // total_bandwidth would become 1.5, and sThrottleFraction would - // become (1024/2) * 1/1.5 = 1024/3: from 2 to 3 services. - // - // In reality, total_bandwidth would rise linear from 1.0 to 1.5 in - // one second if the throttle fraction wasn't changed. However it is - // changed here. The end result is that any change more or less - // linear fades away in one second. - sThrottleFraction = fraction_avg * max_bandwidth / total_bandwidth; - } - if (sThrottleFraction > 1024) - sThrottleFraction = 1024; - if (total_bandwidth > max_bandwidth) - { - sThrottleFraction *= 0.95; - } - - // Throttle this service if it uses too much bandwidth. - if (service_bandwidth > (max_bandwidth * sThrottleFraction / 1024)) - { - return false; // wait - } + // Too much bandwidth is being used, either in total or for this service. + return false; } // Check if it's ok to get a new request based on the total number of requests and increment the threshold if appropriate. @@ -2770,3 +2717,63 @@ bool AIPerService::wantsMoreHTTPRequestsFor(AIPerServicePtr const& per_service) return !reject; } +bool AIPerService::checkBandwidthUsage(U64 sTime_40ms, AIAverage* http_bandwidth_ptr) +{ + if (sNoHTTPBandwidthThrottling) + return false; + + using namespace AICurlPrivate; + + // Truncate the sums to the last second, and get their value. + size_t const max_bandwidth = AIPerService::getHTTPThrottleBandwidth125(); + size_t const total_bandwidth = BufferedCurlEasyRequest::sHTTPBandwidth.truncateData(sTime_40ms); // Bytes received in the past second. + size_t const service_bandwidth = http_bandwidth_ptr->truncateData(sTime_40ms); // Idem for just this service. + if (sTime_40ms > sLastTime_ThrottleFractionAverage_add) + { + sThrottleFractionAverage.addData(sThrottleFraction, sTime_40ms); + // Only add sThrottleFraction once every 40 ms at most. + // It's ok to ignore other values in the same 40 ms because the value only changes on the scale of 1 second. + sLastTime_ThrottleFractionAverage_add = sTime_40ms; + } + double fraction_avg = sThrottleFractionAverage.getAverage(1024.0); // sThrottleFraction averaged over the past second, or 1024 if there is no data. + + // Adjust sThrottleFraction based on total bandwidth usage. + if (total_bandwidth == 0) + sThrottleFraction = 1024; + else + { + // This is the main formula. It can be made plausible by assuming + // an equilibrium where total_bandwidth == max_bandwidth and + // thus sThrottleFraction == fraction_avg for more than a second. + // + // Then, more bandwidth is being used (for example because another + // service starts downloading). Assuming that all services that use + // a significant portion of the bandwidth, the new service included, + // must be throttled (all using the same bandwidth; note that the + // new service is immediately throttled at the same value), then + // the limit should be reduced linear with the fraction: + // max_bandwidth / total_bandwidth. + // + // For example, let max_bandwidth be 1. Let there be two throttled + // services, each using 0.5 (fraction_avg = 1024/2). Let the new + // service use what it can: also 0.5 - then without reduction the + // total_bandwidth would become 1.5, and sThrottleFraction would + // become (1024/2) * 1/1.5 = 1024/3: from 2 to 3 services. + // + // In reality, total_bandwidth would rise linear from 1.0 to 1.5 in + // one second if the throttle fraction wasn't changed. However it is + // changed here. The end result is that any change more or less + // linear fades away in one second. + sThrottleFraction = fraction_avg * max_bandwidth / total_bandwidth; + } + if (sThrottleFraction > 1024) + sThrottleFraction = 1024; + if (total_bandwidth > max_bandwidth) + { + sThrottleFraction *= 0.95; + } + + // Throttle this service if it uses too much bandwidth. + return (service_bandwidth > (max_bandwidth * sThrottleFraction / 1024)); +} +