summaryrefslogtreecommitdiff
path: root/indra/llmessage/llthrottle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage/llthrottle.cpp')
-rw-r--r--indra/llmessage/llthrottle.cpp902
1 files changed, 451 insertions, 451 deletions
diff --git a/indra/llmessage/llthrottle.cpp b/indra/llmessage/llthrottle.cpp
index e659414e8c..0113414d1b 100644
--- a/indra/llmessage/llthrottle.cpp
+++ b/indra/llmessage/llthrottle.cpp
@@ -1,25 +1,25 @@
-/**
+/**
* @file llthrottle.cpp
* @brief LLThrottle class used for network bandwidth control.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -34,108 +34,108 @@
LLThrottle::LLThrottle(const F32 rate)
{
- mRate = rate;
- mAvailable = 0.f;
- mLookaheadSecs = 0.25f;
- mLastSendTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
+ mRate = rate;
+ mAvailable = 0.f;
+ mLookaheadSecs = 0.25f;
+ mLastSendTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
}
void LLThrottle::setRate(const F32 rate)
{
- // Need to accumulate available bits when adjusting the rate.
- mAvailable = getAvailable();
- mLastSendTime = LLMessageSystem::getMessageTimeSeconds();
- mRate = rate;
+ // Need to accumulate available bits when adjusting the rate.
+ mAvailable = getAvailable();
+ mLastSendTime = LLMessageSystem::getMessageTimeSeconds();
+ mRate = rate;
}
F32 LLThrottle::getAvailable()
{
- // use a temporary bits_available
- // since we don't want to change mBitsAvailable every time
- F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime;
- return mAvailable + (mRate * elapsed_time.value());
+ // use a temporary bits_available
+ // since we don't want to change mBitsAvailable every time
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime;
+ return mAvailable + (mRate * elapsed_time.value());
}
BOOL LLThrottle::checkOverflow(const F32 amount)
{
- BOOL retval = TRUE;
-
- F32 lookahead_amount = mRate * mLookaheadSecs;
-
- // use a temporary bits_available
- // since we don't want to change mBitsAvailable every time
- F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime;
- F32 amount_available = mAvailable + (mRate * elapsed_time.value());
-
- if ((amount_available >= lookahead_amount) || (amount_available > amount))
- {
- // ...enough space to send this message
- // Also do if > lookahead so we can use if amount > capped amount.
- retval = FALSE;
- }
-
- return retval;
+ BOOL retval = TRUE;
+
+ F32 lookahead_amount = mRate * mLookaheadSecs;
+
+ // use a temporary bits_available
+ // since we don't want to change mBitsAvailable every time
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime;
+ F32 amount_available = mAvailable + (mRate * elapsed_time.value());
+
+ if ((amount_available >= lookahead_amount) || (amount_available > amount))
+ {
+ // ...enough space to send this message
+ // Also do if > lookahead so we can use if amount > capped amount.
+ retval = FALSE;
+ }
+
+ return retval;
}
BOOL LLThrottle::throttleOverflow(const F32 amount)
{
- F32Seconds elapsed_time;
- F32 lookahead_amount;
- BOOL retval = TRUE;
-
- lookahead_amount = mRate * mLookaheadSecs;
-
- F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
- elapsed_time = mt_sec - mLastSendTime;
- mLastSendTime = mt_sec;
-
- mAvailable += mRate * elapsed_time.value();
-
- if (mAvailable >= lookahead_amount)
- {
- // ...channel completely open, so allow send regardless
- // of size. This allows sends on very low BPS channels.
- mAvailable = lookahead_amount;
- retval = FALSE;
- }
- else if (mAvailable > amount)
- {
- // ...enough space to send this message
- retval = FALSE;
- }
-
- // We actually already sent the bits.
- mAvailable -= amount;
-
- // What if bitsavailable goes negative?
- // That's OK, because it means someone is banging on the channel,
- // so we need some time to recover.
-
- return retval;
+ F32Seconds elapsed_time;
+ F32 lookahead_amount;
+ BOOL retval = TRUE;
+
+ lookahead_amount = mRate * mLookaheadSecs;
+
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+ elapsed_time = mt_sec - mLastSendTime;
+ mLastSendTime = mt_sec;
+
+ mAvailable += mRate * elapsed_time.value();
+
+ if (mAvailable >= lookahead_amount)
+ {
+ // ...channel completely open, so allow send regardless
+ // of size. This allows sends on very low BPS channels.
+ mAvailable = lookahead_amount;
+ retval = FALSE;
+ }
+ else if (mAvailable > amount)
+ {
+ // ...enough space to send this message
+ retval = FALSE;
+ }
+
+ // We actually already sent the bits.
+ mAvailable -= amount;
+
+ // What if bitsavailable goes negative?
+ // That's OK, because it means someone is banging on the channel,
+ // so we need some time to recover.
+
+ return retval;
}
-const F32 THROTTLE_LOOKAHEAD_TIME = 1.f; // seconds
+const F32 THROTTLE_LOOKAHEAD_TIME = 1.f; // seconds
// Make sure that we don't set above these
// values, even if the client asks to be set
// higher
-// Note that these values are replicated on the
+// Note that these values are replicated on the
// client side to set max bandwidth throttling there,
// in llviewerthrottle.cpp. These values are the sum
// of the top two tiers of bandwidth there.
F32 gThrottleMaximumBPS[TC_EOF] =
{
- 150000.f, // TC_RESEND
- 170000.f, // TC_LAND
- 34000.f, // TC_WIND
- 34000.f, // TC_CLOUD
- 446000.f, // TC_TASK
- 446000.f, // TC_TEXTURE
- 220000.f, // TC_ASSET
+ 150000.f, // TC_RESEND
+ 170000.f, // TC_LAND
+ 34000.f, // TC_WIND
+ 34000.f, // TC_CLOUD
+ 446000.f, // TC_TASK
+ 446000.f, // TC_TEXTURE
+ 220000.f, // TC_ASSET
};
// Start low until viewer informs us of capability
@@ -146,13 +146,13 @@ F32 gThrottleMaximumBPS[TC_EOF] =
F32 gThrottleDefaultBPS[TC_EOF] =
{
- 100000.f, // TC_RESEND
- 4000.f, // TC_LAND
- 4000.f, // TC_WIND
- 4000.f, // TC_CLOUD
- 4000.f, // TC_TASK
- 4000.f, // TC_TEXTURE
- 100000.f, // TC_ASSET
+ 100000.f, // TC_RESEND
+ 4000.f, // TC_LAND
+ 4000.f, // TC_WIND
+ 4000.f, // TC_CLOUD
+ 4000.f, // TC_TASK
+ 4000.f, // TC_TEXTURE
+ 100000.f, // TC_ASSET
};
// Don't throttle down lower than this
@@ -160,61 +160,61 @@ F32 gThrottleDefaultBPS[TC_EOF] =
// wont.
F32 gThrottleMinimumBPS[TC_EOF] =
{
- 10000.f, // TC_RESEND
- 10000.f, // TC_LAND
- 4000.f, // TC_WIND
- 4000.f, // TC_CLOUD
- 20000.f, // TC_TASK
- 10000.f, // TC_TEXTURE
- 10000.f, // TC_ASSET
+ 10000.f, // TC_RESEND
+ 10000.f, // TC_LAND
+ 4000.f, // TC_WIND
+ 4000.f, // TC_CLOUD
+ 20000.f, // TC_TASK
+ 10000.f, // TC_TEXTURE
+ 10000.f, // TC_ASSET
};
const char* THROTTLE_NAMES[TC_EOF] =
{
- "Resend ",
- "Land ",
- "Wind ",
- "Cloud ",
- "Task ",
- "Texture",
- "Asset "
+ "Resend ",
+ "Land ",
+ "Wind ",
+ "Cloud ",
+ "Task ",
+ "Texture",
+ "Asset "
};
LLThrottleGroup::LLThrottleGroup()
{
- S32 i;
- for (i = 0; i < TC_EOF; i++)
- {
- mThrottleTotal[i] = gThrottleDefaultBPS[i];
- mNominalBPS[i] = gThrottleDefaultBPS[i];
- }
-
- resetDynamicAdjust();
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ mThrottleTotal[i] = gThrottleDefaultBPS[i];
+ mNominalBPS[i] = gThrottleDefaultBPS[i];
+ }
+
+ resetDynamicAdjust();
}
void LLThrottleGroup::packThrottle(LLDataPacker &dp) const
{
- S32 i;
- for (i = 0; i < TC_EOF; i++)
- {
- dp.packF32(mThrottleTotal[i], "Throttle");
- }
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ dp.packF32(mThrottleTotal[i], "Throttle");
+ }
}
void LLThrottleGroup::unpackThrottle(LLDataPacker &dp)
{
- S32 i;
- for (i = 0; i < TC_EOF; i++)
- {
- F32 temp_throttle;
- dp.unpackF32(temp_throttle, "Throttle");
- temp_throttle = llclamp(temp_throttle, 0.f, 2250000.f);
- mThrottleTotal[i] = temp_throttle;
- if(mThrottleTotal[i] > gThrottleMaximumBPS[i])
- {
- mThrottleTotal[i] = gThrottleMaximumBPS[i];
- }
- }
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ F32 temp_throttle;
+ dp.unpackF32(temp_throttle, "Throttle");
+ temp_throttle = llclamp(temp_throttle, 0.f, 2250000.f);
+ mThrottleTotal[i] = temp_throttle;
+ if(mThrottleTotal[i] > gThrottleMaximumBPS[i])
+ {
+ mThrottleTotal[i] = gThrottleMaximumBPS[i];
+ }
+ }
}
// Call this whenever mNominalBPS changes. Need to reset
@@ -222,356 +222,356 @@ void LLThrottleGroup::unpackThrottle(LLDataPacker &dp)
// into NOT resetting the system.
void LLThrottleGroup::resetDynamicAdjust()
{
- F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
- S32 i;
- for (i = 0; i < TC_EOF; i++)
- {
- mCurrentBPS[i] = mNominalBPS[i];
- mBitsAvailable[i] = mNominalBPS[i] * THROTTLE_LOOKAHEAD_TIME;
- mLastSendTime[i] = mt_sec;
- mBitsSentThisPeriod[i] = 0;
- mBitsSentHistory[i] = 0;
- }
- mDynamicAdjustTime = mt_sec;
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ mCurrentBPS[i] = mNominalBPS[i];
+ mBitsAvailable[i] = mNominalBPS[i] * THROTTLE_LOOKAHEAD_TIME;
+ mLastSendTime[i] = mt_sec;
+ mBitsSentThisPeriod[i] = 0;
+ mBitsSentHistory[i] = 0;
+ }
+ mDynamicAdjustTime = mt_sec;
}
BOOL LLThrottleGroup::setNominalBPS(F32* throttle_vec)
{
- BOOL changed = FALSE;
- S32 i;
- for (i = 0; i < TC_EOF; i++)
- {
- if (mNominalBPS[i] != throttle_vec[i])
- {
- changed = TRUE;
- mNominalBPS[i] = throttle_vec[i];
- }
- }
-
- // If we changed the nominal settings, reset the dynamic
- // adjustment subsystem.
- if (changed)
- {
- resetDynamicAdjust();
- }
-
- return changed;
+ BOOL changed = FALSE;
+ S32 i;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mNominalBPS[i] != throttle_vec[i])
+ {
+ changed = TRUE;
+ mNominalBPS[i] = throttle_vec[i];
+ }
+ }
+
+ // If we changed the nominal settings, reset the dynamic
+ // adjustment subsystem.
+ if (changed)
+ {
+ resetDynamicAdjust();
+ }
+
+ return changed;
}
// Return bits available in the channel
-S32 LLThrottleGroup::getAvailable(S32 throttle_cat)
+S32 LLThrottleGroup::getAvailable(S32 throttle_cat)
{
- S32 retval = 0;
-
- F32 category_bps = mCurrentBPS[throttle_cat];
- F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
-
- // use a temporary bits_available
- // since we don't want to change mBitsAvailable every time
- F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat];
- F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value());
-
- if (bits_available >= lookahead_bits)
- {
- retval = (S32) gThrottleMaximumBPS[throttle_cat];
- }
- else
- {
- retval = (S32) bits_available;
- }
-
- return retval;
+ S32 retval = 0;
+
+ F32 category_bps = mCurrentBPS[throttle_cat];
+ F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
+
+ // use a temporary bits_available
+ // since we don't want to change mBitsAvailable every time
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat];
+ F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value());
+
+ if (bits_available >= lookahead_bits)
+ {
+ retval = (S32) gThrottleMaximumBPS[throttle_cat];
+ }
+ else
+ {
+ retval = (S32) bits_available;
+ }
+
+ return retval;
}
BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits)
{
- BOOL retval = TRUE;
-
- F32 category_bps = mCurrentBPS[throttle_cat];
- F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
-
- // use a temporary bits_available
- // since we don't want to change mBitsAvailable every time
- F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat];
- F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value());
-
- if (bits_available >= lookahead_bits)
- {
- // ...channel completely open, so allow send regardless
- // of size. This allows sends on very low BPS channels.
- mBitsAvailable[throttle_cat] = lookahead_bits;
- retval = FALSE;
- }
- else if ( bits_available > bits )
- {
- // ...enough space to send this message
- retval = FALSE;
- }
-
- return retval;
+ BOOL retval = TRUE;
+
+ F32 category_bps = mCurrentBPS[throttle_cat];
+ F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
+
+ // use a temporary bits_available
+ // since we don't want to change mBitsAvailable every time
+ F32Seconds elapsed_time = LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat];
+ F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time.value());
+
+ if (bits_available >= lookahead_bits)
+ {
+ // ...channel completely open, so allow send regardless
+ // of size. This allows sends on very low BPS channels.
+ mBitsAvailable[throttle_cat] = lookahead_bits;
+ retval = FALSE;
+ }
+ else if ( bits_available > bits )
+ {
+ // ...enough space to send this message
+ retval = FALSE;
+ }
+
+ return retval;
}
BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits)
{
- F32Seconds elapsed_time;
- F32 category_bps;
- F32 lookahead_bits;
- BOOL retval = TRUE;
-
- category_bps = mCurrentBPS[throttle_cat];
- lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
-
- F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
- elapsed_time = mt_sec - mLastSendTime[throttle_cat];
- mLastSendTime[throttle_cat] = mt_sec;
- mBitsAvailable[throttle_cat] += category_bps * elapsed_time.value();
-
- if (mBitsAvailable[throttle_cat] >= lookahead_bits)
- {
- // ...channel completely open, so allow send regardless
- // of size. This allows sends on very low BPS channels.
- mBitsAvailable[throttle_cat] = lookahead_bits;
- retval = FALSE;
- }
- else if ( mBitsAvailable[throttle_cat] > bits )
- {
- // ...enough space to send this message
- retval = FALSE;
- }
-
- // We actually already sent the bits.
- mBitsAvailable[throttle_cat] -= bits;
-
- mBitsSentThisPeriod[throttle_cat] += bits;
-
- // What if bitsavailable goes negative?
- // That's OK, because it means someone is banging on the channel,
- // so we need some time to recover.
-
- return retval;
+ F32Seconds elapsed_time;
+ F32 category_bps;
+ F32 lookahead_bits;
+ BOOL retval = TRUE;
+
+ category_bps = mCurrentBPS[throttle_cat];
+ lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
+
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+ elapsed_time = mt_sec - mLastSendTime[throttle_cat];
+ mLastSendTime[throttle_cat] = mt_sec;
+ mBitsAvailable[throttle_cat] += category_bps * elapsed_time.value();
+
+ if (mBitsAvailable[throttle_cat] >= lookahead_bits)
+ {
+ // ...channel completely open, so allow send regardless
+ // of size. This allows sends on very low BPS channels.
+ mBitsAvailable[throttle_cat] = lookahead_bits;
+ retval = FALSE;
+ }
+ else if ( mBitsAvailable[throttle_cat] > bits )
+ {
+ // ...enough space to send this message
+ retval = FALSE;
+ }
+
+ // We actually already sent the bits.
+ mBitsAvailable[throttle_cat] -= bits;
+
+ mBitsSentThisPeriod[throttle_cat] += bits;
+
+ // What if bitsavailable goes negative?
+ // That's OK, because it means someone is banging on the channel,
+ // so we need some time to recover.
+
+ return retval;
}
BOOL LLThrottleGroup::dynamicAdjust()
{
- const F32Seconds DYNAMIC_ADJUST_TIME(1.0f);
- const F32 CURRENT_PERIOD_WEIGHT = .25f; // how much weight to give to last period while determining BPS utilization
- const F32 BUSY_PERCENT = 0.75f; // if use more than this fraction of BPS, you are busy
- const F32 IDLE_PERCENT = 0.70f; // if use less than this fraction, you are "idle"
- const F32 TRANSFER_PERCENT = 0.90f; // how much unused bandwidth to take away each adjustment
- const F32 RECOVER_PERCENT = 0.25f; // how much to give back during recovery phase
-
- S32 i;
-
- F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
-
- // Only dynamically adjust every few seconds
- if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME)
- {
- return FALSE;
- }
- mDynamicAdjustTime = mt_sec;
-
- // Update historical information
- for (i = 0; i < TC_EOF; i++)
- {
- if (mBitsSentHistory[i] == 0)
- {
- // first run, just copy current period
- mBitsSentHistory[i] = mBitsSentThisPeriod[i];
- }
- else
- {
- // have some history, so weight accordingly
- mBitsSentHistory[i] = (1.f - CURRENT_PERIOD_WEIGHT) * mBitsSentHistory[i]
- + CURRENT_PERIOD_WEIGHT * mBitsSentThisPeriod[i];
- }
-
- mBitsSentThisPeriod[i] = 0;
- }
-
- // Look for busy channels
- // TODO: Fold into loop above.
- BOOL channels_busy = FALSE;
- F32 busy_nominal_sum = 0;
- BOOL channel_busy[TC_EOF];
- BOOL channel_idle[TC_EOF];
- BOOL channel_over_nominal[TC_EOF];
-
- for (i = 0; i < TC_EOF; i++)
- {
- // Is this a busy channel?
- if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i])
- {
- // this channel is busy
- channels_busy = TRUE;
- busy_nominal_sum += mNominalBPS[i]; // use for allocation of pooled idle bandwidth
- channel_busy[i] = TRUE;
- }
- else
- {
- channel_busy[i] = FALSE;
- }
-
- // Is this an idle channel?
- if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) &&
- (mBitsAvailable[i] > 0))
- {
- channel_idle[i] = TRUE;
- }
- else
- {
- channel_idle[i] = FALSE;
- }
-
- // Is this an overpumped channel?
- if (mCurrentBPS[i] > mNominalBPS[i])
- {
- channel_over_nominal[i] = TRUE;
- }
- else
- {
- channel_over_nominal[i] = FALSE;
- }
- }
-
- if (channels_busy)
- {
- // Some channels are busy. Let's see if we can get them some bandwidth.
- F32 used_bps;
- F32 avail_bps;
- F32 transfer_bps;
-
- F32 pool_bps = 0;
-
- for (i = 0; i < TC_EOF; i++)
- {
- if (channel_idle[i] || channel_over_nominal[i] )
- {
- // Either channel i is idle, or has been overpumped.
- // Therefore it's a candidate to give up some bandwidth.
- // Figure out how much bandwidth it has been using, and how
- // much is available to steal.
- used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME.value();
-
- // CRO make sure to keep a minimum amount of throttle available
- // CRO NB: channels set to < MINIMUM_BPS will never give up bps,
- // which is correct I think
- if (used_bps < gThrottleMinimumBPS[i])
- {
- used_bps = gThrottleMinimumBPS[i];
- }
-
- if (channel_over_nominal[i])
- {
- F32 unused_current = mCurrentBPS[i] - used_bps;
- avail_bps = llmax(mCurrentBPS[i] - mNominalBPS[i], unused_current);
- }
- else
- {
- avail_bps = mCurrentBPS[i] - used_bps;
- }
-
- //LL_INFOS() << i << " avail " << avail_bps << LL_ENDL;
-
- // Historically, a channel could have used more than its current share,
- // even if it's idle right now.
- // Make sure we don't steal too much.
- if (avail_bps < 0)
- {
- continue;
- }
-
- // Transfer some bandwidth from this channel into the global pool.
- transfer_bps = avail_bps * TRANSFER_PERCENT;
- mCurrentBPS[i] -= transfer_bps;
- pool_bps += transfer_bps;
- }
- }
-
- //LL_INFOS() << "Pool BPS: " << pool_bps << LL_ENDL;
- // Now redistribute the bandwidth to busy channels.
- F32 unused_bps = 0.f;
-
- for (i = 0; i < TC_EOF; i++)
- {
- if (channel_busy[i])
- {
- F32 add_amount = pool_bps * (mNominalBPS[i] / busy_nominal_sum);
- //LL_INFOS() << "Busy " << i << " gets " << pool_bps << LL_ENDL;
- mCurrentBPS[i] += add_amount;
-
- // CRO: make sure this doesn't get too huge
- // JC - Actually, need to let mCurrentBPS go less than nominal, otherwise
- // you aren't allowing bandwidth to actually be moved from one channel
- // to another.
- // *TODO: If clamping high end, would be good to re-
- // allocate to other channels in the above code.
- const F32 MAX_BPS = 4 * mNominalBPS[i];
- if (mCurrentBPS[i] > MAX_BPS)
- {
- F32 overage = mCurrentBPS[i] - MAX_BPS;
- mCurrentBPS[i] -= overage;
- unused_bps += overage;
- }
-
- // Paranoia
- if (mCurrentBPS[i] < gThrottleMinimumBPS[i])
- {
- mCurrentBPS[i] = gThrottleMinimumBPS[i];
- }
- }
- }
-
- // For fun, add the overage back in to objects
- if (unused_bps > 0.f)
- {
- mCurrentBPS[TC_TASK] += unused_bps;
- }
- }
- else
- {
- // No one is busy.
- // Make the channel allocations seek toward nominal.
-
- // Look for overpumped channels
- F32 starved_nominal_sum = 0;
- F32 avail_bps = 0;
- F32 transfer_bps = 0;
- F32 pool_bps = 0;
- for (i = 0; i < TC_EOF; i++)
- {
- if (mCurrentBPS[i] > mNominalBPS[i])
- {
- avail_bps = (mCurrentBPS[i] - mNominalBPS[i]);
- transfer_bps = avail_bps * RECOVER_PERCENT;
-
- mCurrentBPS[i] -= transfer_bps;
- pool_bps += transfer_bps;
- }
- }
-
- // Evenly distribute bandwidth to channels currently
- // using less than nominal.
- for (i = 0; i < TC_EOF; i++)
- {
- if (mCurrentBPS[i] < mNominalBPS[i])
- {
- // We're going to weight allocations by nominal BPS.
- starved_nominal_sum += mNominalBPS[i];
- }
- }
-
- for (i = 0; i < TC_EOF; i++)
- {
- if (mCurrentBPS[i] < mNominalBPS[i])
- {
- // Distribute bandwidth according to nominal allocation ratios.
- mCurrentBPS[i] += pool_bps * (mNominalBPS[i] / starved_nominal_sum);
- }
- }
- }
- return TRUE;
+ const F32Seconds DYNAMIC_ADJUST_TIME(1.0f);
+ const F32 CURRENT_PERIOD_WEIGHT = .25f; // how much weight to give to last period while determining BPS utilization
+ const F32 BUSY_PERCENT = 0.75f; // if use more than this fraction of BPS, you are busy
+ const F32 IDLE_PERCENT = 0.70f; // if use less than this fraction, you are "idle"
+ const F32 TRANSFER_PERCENT = 0.90f; // how much unused bandwidth to take away each adjustment
+ const F32 RECOVER_PERCENT = 0.25f; // how much to give back during recovery phase
+
+ S32 i;
+
+ F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();
+
+ // Only dynamically adjust every few seconds
+ if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME)
+ {
+ return FALSE;
+ }
+ mDynamicAdjustTime = mt_sec;
+
+ // Update historical information
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mBitsSentHistory[i] == 0)
+ {
+ // first run, just copy current period
+ mBitsSentHistory[i] = mBitsSentThisPeriod[i];
+ }
+ else
+ {
+ // have some history, so weight accordingly
+ mBitsSentHistory[i] = (1.f - CURRENT_PERIOD_WEIGHT) * mBitsSentHistory[i]
+ + CURRENT_PERIOD_WEIGHT * mBitsSentThisPeriod[i];
+ }
+
+ mBitsSentThisPeriod[i] = 0;
+ }
+
+ // Look for busy channels
+ // TODO: Fold into loop above.
+ BOOL channels_busy = FALSE;
+ F32 busy_nominal_sum = 0;
+ BOOL channel_busy[TC_EOF];
+ BOOL channel_idle[TC_EOF];
+ BOOL channel_over_nominal[TC_EOF];
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ // Is this a busy channel?
+ if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i])
+ {
+ // this channel is busy
+ channels_busy = TRUE;
+ busy_nominal_sum += mNominalBPS[i]; // use for allocation of pooled idle bandwidth
+ channel_busy[i] = TRUE;
+ }
+ else
+ {
+ channel_busy[i] = FALSE;
+ }
+
+ // Is this an idle channel?
+ if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) &&
+ (mBitsAvailable[i] > 0))
+ {
+ channel_idle[i] = TRUE;
+ }
+ else
+ {
+ channel_idle[i] = FALSE;
+ }
+
+ // Is this an overpumped channel?
+ if (mCurrentBPS[i] > mNominalBPS[i])
+ {
+ channel_over_nominal[i] = TRUE;
+ }
+ else
+ {
+ channel_over_nominal[i] = FALSE;
+ }
+ }
+
+ if (channels_busy)
+ {
+ // Some channels are busy. Let's see if we can get them some bandwidth.
+ F32 used_bps;
+ F32 avail_bps;
+ F32 transfer_bps;
+
+ F32 pool_bps = 0;
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (channel_idle[i] || channel_over_nominal[i] )
+ {
+ // Either channel i is idle, or has been overpumped.
+ // Therefore it's a candidate to give up some bandwidth.
+ // Figure out how much bandwidth it has been using, and how
+ // much is available to steal.
+ used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME.value();
+
+ // CRO make sure to keep a minimum amount of throttle available
+ // CRO NB: channels set to < MINIMUM_BPS will never give up bps,
+ // which is correct I think
+ if (used_bps < gThrottleMinimumBPS[i])
+ {
+ used_bps = gThrottleMinimumBPS[i];
+ }
+
+ if (channel_over_nominal[i])
+ {
+ F32 unused_current = mCurrentBPS[i] - used_bps;
+ avail_bps = llmax(mCurrentBPS[i] - mNominalBPS[i], unused_current);
+ }
+ else
+ {
+ avail_bps = mCurrentBPS[i] - used_bps;
+ }
+
+ //LL_INFOS() << i << " avail " << avail_bps << LL_ENDL;
+
+ // Historically, a channel could have used more than its current share,
+ // even if it's idle right now.
+ // Make sure we don't steal too much.
+ if (avail_bps < 0)
+ {
+ continue;
+ }
+
+ // Transfer some bandwidth from this channel into the global pool.
+ transfer_bps = avail_bps * TRANSFER_PERCENT;
+ mCurrentBPS[i] -= transfer_bps;
+ pool_bps += transfer_bps;
+ }
+ }
+
+ //LL_INFOS() << "Pool BPS: " << pool_bps << LL_ENDL;
+ // Now redistribute the bandwidth to busy channels.
+ F32 unused_bps = 0.f;
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (channel_busy[i])
+ {
+ F32 add_amount = pool_bps * (mNominalBPS[i] / busy_nominal_sum);
+ //LL_INFOS() << "Busy " << i << " gets " << pool_bps << LL_ENDL;
+ mCurrentBPS[i] += add_amount;
+
+ // CRO: make sure this doesn't get too huge
+ // JC - Actually, need to let mCurrentBPS go less than nominal, otherwise
+ // you aren't allowing bandwidth to actually be moved from one channel
+ // to another.
+ // *TODO: If clamping high end, would be good to re-
+ // allocate to other channels in the above code.
+ const F32 MAX_BPS = 4 * mNominalBPS[i];
+ if (mCurrentBPS[i] > MAX_BPS)
+ {
+ F32 overage = mCurrentBPS[i] - MAX_BPS;
+ mCurrentBPS[i] -= overage;
+ unused_bps += overage;
+ }
+
+ // Paranoia
+ if (mCurrentBPS[i] < gThrottleMinimumBPS[i])
+ {
+ mCurrentBPS[i] = gThrottleMinimumBPS[i];
+ }
+ }
+ }
+
+ // For fun, add the overage back in to objects
+ if (unused_bps > 0.f)
+ {
+ mCurrentBPS[TC_TASK] += unused_bps;
+ }
+ }
+ else
+ {
+ // No one is busy.
+ // Make the channel allocations seek toward nominal.
+
+ // Look for overpumped channels
+ F32 starved_nominal_sum = 0;
+ F32 avail_bps = 0;
+ F32 transfer_bps = 0;
+ F32 pool_bps = 0;
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mCurrentBPS[i] > mNominalBPS[i])
+ {
+ avail_bps = (mCurrentBPS[i] - mNominalBPS[i]);
+ transfer_bps = avail_bps * RECOVER_PERCENT;
+
+ mCurrentBPS[i] -= transfer_bps;
+ pool_bps += transfer_bps;
+ }
+ }
+
+ // Evenly distribute bandwidth to channels currently
+ // using less than nominal.
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mCurrentBPS[i] < mNominalBPS[i])
+ {
+ // We're going to weight allocations by nominal BPS.
+ starved_nominal_sum += mNominalBPS[i];
+ }
+ }
+
+ for (i = 0; i < TC_EOF; i++)
+ {
+ if (mCurrentBPS[i] < mNominalBPS[i])
+ {
+ // Distribute bandwidth according to nominal allocation ratios.
+ mCurrentBPS[i] += pool_bps * (mNominalBPS[i] / starved_nominal_sum);
+ }
+ }
+ }
+ return TRUE;
}