llviewerthrottle.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 #include "llviewerthrottle.h"
00034 
00035 #include "llviewercontrol.h"
00036 #include "message.h"
00037 #include "llagent.h"
00038 #include "llframetimer.h"
00039 #include "llviewerstats.h"
00040 #include "lldatapacker.h"
00041 
00042 // consts
00043 
00044 // The viewer is allowed to set the under-the-hood bandwidth to 50%
00045 // greater than the prefs UI shows, under the assumption that the
00046 // viewer won't receive all the different message types at once.
00047 // I didn't design this, don't know who did. JC
00048 const F32 MAX_FRACTIONAL = 1.5f;
00049 const F32 MIN_FRACTIONAL = 0.2f;
00050 
00051 const F32 MIN_BANDWIDTH = 50.f;
00052 const F32 MAX_BANDWIDTH = 1500.f;
00053 const F32 STEP_FRACTIONAL = 0.1f;
00054 const F32 TIGHTEN_THROTTLE_THRESHOLD = 3.0f; // packet loss % per s
00055 const F32 EASE_THROTTLE_THRESHOLD = 0.5f; // packet loss % per s
00056 const F32 DYNAMIC_UPDATE_DURATION = 5.0f; // seconds
00057 
00058 LLViewerThrottle gViewerThrottle;
00059 
00060 // static
00061 const char *LLViewerThrottle::sNames[TC_EOF] = {
00062                                                         "Resend",
00063                                                         "Land",
00064                                                         "Wind",
00065                                                         "Cloud",
00066                                                         "Task",
00067                                                         "Texture",
00068                                                         "Asset"
00069                                                         };
00070 
00071 
00072 // Bandwidth settings for different bit rates, they're interpolated/extrapolated.
00073 //                                Resend Land Wind Cloud Task Texture Asset
00074 const F32 BW_PRESET_50[TC_EOF]   = {   5,  10,   3,   3,  10,  10,   9 };
00075 const F32 BW_PRESET_300[TC_EOF]  = {  30,  40,   9,   9,  86,  86,  40 };
00076 const F32 BW_PRESET_500[TC_EOF]  = {  50,  70,  14,  14, 136, 136,  80 };
00077 const F32 BW_PRESET_1000[TC_EOF] = { 100, 100,  20,  20, 310, 310, 140 };
00078 
00079 LLViewerThrottleGroup::LLViewerThrottleGroup()
00080 {
00081         S32 i;
00082         for (i = 0; i < TC_EOF; i++)
00083         {
00084                 mThrottles[i] = 0.f;
00085         }
00086         mThrottleTotal = 0.f;
00087 }
00088 
00089 
00090 LLViewerThrottleGroup::LLViewerThrottleGroup(const F32 settings[])
00091 {
00092         mThrottleTotal = 0.f;
00093         S32 i;
00094         for (i = 0; i < TC_EOF; i++)
00095         {
00096                 mThrottles[i] = settings[i];
00097                 mThrottleTotal += settings[i];
00098         }
00099 }
00100 
00101 
00102 LLViewerThrottleGroup LLViewerThrottleGroup::operator*(const F32 frac) const
00103 {
00104         LLViewerThrottleGroup res;
00105         res.mThrottleTotal = 0.f;
00106 
00107         S32 i;
00108         for (i = 0; i < TC_EOF; i++)
00109         {
00110                 res.mThrottles[i] = mThrottles[i] * frac;
00111                 res.mThrottleTotal += res.mThrottles[i];
00112         }
00113 
00114         return res;
00115 }
00116 
00117 
00118 LLViewerThrottleGroup LLViewerThrottleGroup::operator+(const LLViewerThrottleGroup &b) const
00119 {
00120         LLViewerThrottleGroup res;
00121         res.mThrottleTotal = 0.f;
00122 
00123         S32 i;
00124         for (i = 0; i < TC_EOF; i++)
00125         {
00126                 res.mThrottles[i] = mThrottles[i] + b.mThrottles[i];
00127                 res.mThrottleTotal += res.mThrottles[i];
00128         }
00129 
00130         return res;
00131 }
00132 
00133 
00134 LLViewerThrottleGroup LLViewerThrottleGroup::operator-(const LLViewerThrottleGroup &b) const
00135 {
00136         LLViewerThrottleGroup res;
00137         res.mThrottleTotal = 0.f;
00138 
00139         S32 i;
00140         for (i = 0; i < TC_EOF; i++)
00141         {
00142                 res.mThrottles[i] = mThrottles[i] - b.mThrottles[i];
00143                 res.mThrottleTotal += res.mThrottles[i];
00144         }
00145 
00146         return res;
00147 }
00148 
00149 
00150 void LLViewerThrottleGroup::sendToSim() const
00151 {
00152         llinfos << "Sending throttle settings, total BW " << mThrottleTotal << llendl;
00153         LLMessageSystem* msg = gMessageSystem;
00154 
00155         msg->newMessageFast(_PREHASH_AgentThrottle);
00156         msg->nextBlockFast(_PREHASH_AgentData);
00157         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00158         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00159         msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
00160 
00161         msg->nextBlockFast(_PREHASH_Throttle);
00162         msg->addU32Fast(_PREHASH_GenCounter, 0);
00163 
00164         // Pack up the throttle data
00165         U8 tmp[64];
00166         LLDataPackerBinaryBuffer dp(tmp, MAX_THROTTLE_SIZE);
00167         S32 i;
00168         for (i = 0; i < TC_EOF; i++)
00169         {
00170                 //sim wants BPS, not KBPS
00171                 dp.packF32(mThrottles[i] * 1024.0f, "Throttle");
00172         }
00173         S32 len = dp.getCurrentSize();
00174         msg->addBinaryDataFast(_PREHASH_Throttles, tmp, len);
00175 
00176         gAgent.sendReliableMessage();
00177 }
00178 
00179 
00180 void LLViewerThrottleGroup::dump()
00181 {
00182         S32 i;
00183         for (i = 0; i < TC_EOF; i++)
00184         {
00185                 LL_DEBUGS("Throttle") << LLViewerThrottle::sNames[i] << ": " << mThrottles[i] << LL_ENDL;
00186         }
00187         LL_DEBUGS("Throttle") << "Total: " << mThrottleTotal << LL_ENDL;
00188 }
00189 
00190 class LLBPSListener : public LLSimpleListener
00191 {
00192 public:
00193         virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
00194         {
00195                 gViewerThrottle.setMaxBandwidth((F32) event->getValue().asReal()*1024);
00196                 return true;
00197         }
00198 };
00199 
00200 LLViewerThrottle::LLViewerThrottle() :
00201         mMaxBandwidth(0.f),
00202         mCurrentBandwidth(0.f),
00203         mThrottleFrac(1.f)
00204 {
00205         // Need to be pushed on in bandwidth order
00206         mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_50));
00207         mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_300));
00208         mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_500));
00209         mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_1000));
00210 }
00211 
00212 
00213 void LLViewerThrottle::setMaxBandwidth(F32 kbits_per_second, BOOL from_event)
00214 {
00215         if (!from_event)
00216         {
00217                 gSavedSettings.setF32("ThrottleBandwidthKBPS", kbits_per_second);
00218         }
00219         gViewerThrottle.load();
00220 
00221         if (gAgent.getRegion())
00222         {
00223                 gViewerThrottle.sendToSim();
00224         }
00225 }
00226 
00227 void LLViewerThrottle::load()
00228 {
00229         mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS")*1024;
00230         resetDynamicThrottle();
00231         mCurrent.dump();
00232 }
00233 
00234 
00235 void LLViewerThrottle::save() const
00236 {
00237         gSavedSettings.setF32("ThrottleBandwidthKBPS", mMaxBandwidth/1024);
00238 }
00239 
00240 
00241 void LLViewerThrottle::sendToSim() const
00242 {
00243         mCurrent.sendToSim();
00244 }
00245 
00246 
00247 LLViewerThrottleGroup LLViewerThrottle::getThrottleGroup(const F32 bandwidth_kbps)
00248 {
00249         //Clamp the bandwidth users can set.
00250         F32 set_bandwidth = llclamp(bandwidth_kbps, MIN_BANDWIDTH, MAX_BANDWIDTH);
00251 
00252         S32 count = mPresets.size();
00253 
00254         S32 i;
00255         for (i = 0; i < count; i++)
00256         {
00257                 if (mPresets[i].getTotal() > set_bandwidth)
00258                 {
00259                         break;
00260                 }
00261         }
00262 
00263         if (i == 0)
00264         {
00265                 // We return the minimum if it's less than the minimum
00266                 return mPresets[0];
00267         }
00268         else if (i == count)
00269         {
00270                 // Higher than the highest preset, we extrapolate out based on the
00271                 // last two presets.  This allows us to keep certain throttle channels from
00272                 // growing in bandwidth
00273                 F32 delta_bw = set_bandwidth - mPresets[count-1].getTotal();
00274                 LLViewerThrottleGroup delta_throttle = mPresets[count - 1] - mPresets[count - 2];
00275                 F32 delta_total = delta_throttle.getTotal();
00276                 F32 delta_frac = delta_bw / delta_total;
00277                 delta_throttle = delta_throttle * delta_frac;
00278                 return mPresets[count-1] + delta_throttle;
00279         }
00280         else
00281         {
00282                 // In between two presets, just interpolate
00283                 F32 delta_bw = set_bandwidth - mPresets[i - 1].getTotal();
00284                 LLViewerThrottleGroup delta_throttle = mPresets[i] - mPresets[i - 1];
00285                 F32 delta_total = delta_throttle.getTotal();
00286                 F32 delta_frac = delta_bw / delta_total;
00287                 delta_throttle = delta_throttle * delta_frac;
00288                 return mPresets[i - 1] + delta_throttle;
00289         }
00290 }
00291 
00292 
00293 // static
00294 void LLViewerThrottle::resetDynamicThrottle()
00295 {
00296         mThrottleFrac = MAX_FRACTIONAL;
00297 
00298         mCurrentBandwidth = mMaxBandwidth*MAX_FRACTIONAL;
00299         mCurrent = getThrottleGroup(mCurrentBandwidth / 1024.0f);
00300 }
00301 
00302 void LLViewerThrottle::updateDynamicThrottle()
00303 {
00304         if (mUpdateTimer.getElapsedTimeF32() < DYNAMIC_UPDATE_DURATION)
00305         {
00306                 return;
00307         }
00308         mUpdateTimer.reset();
00309 
00310         if (LLViewerStats::getInstance()->mPacketsLostPercentStat.getMean() > TIGHTEN_THROTTLE_THRESHOLD)
00311         {
00312                 if (mThrottleFrac <= MIN_FRACTIONAL || mCurrentBandwidth / 1024.0f <= MIN_BANDWIDTH)
00313                 {
00314                         return;
00315                 }
00316                 mThrottleFrac -= STEP_FRACTIONAL;
00317                 mThrottleFrac = llmax(MIN_FRACTIONAL, mThrottleFrac);
00318                 mCurrentBandwidth = mMaxBandwidth * mThrottleFrac;
00319                 mCurrent = getThrottleGroup(mCurrentBandwidth / 1024.0f);
00320                 mCurrent.sendToSim();
00321                 llinfos << "Tightening network throttle to " << mCurrentBandwidth << llendl;
00322         }
00323         else if (LLViewerStats::getInstance()->mPacketsLostPercentStat.getMean() <= EASE_THROTTLE_THRESHOLD)
00324         {
00325                 if (mThrottleFrac >= MAX_FRACTIONAL || mCurrentBandwidth / 1024.0f >= MAX_BANDWIDTH)
00326                 {
00327                         return;
00328                 }
00329                 mThrottleFrac += STEP_FRACTIONAL;
00330                 mThrottleFrac = llmin(MAX_FRACTIONAL, mThrottleFrac);
00331                 mCurrentBandwidth = mMaxBandwidth * mThrottleFrac;
00332                 mCurrent = getThrottleGroup(mCurrentBandwidth/1024.0f);
00333                 mCurrent.sendToSim();
00334                 llinfos << "Easing network throttle to " << mCurrentBandwidth << llendl;
00335         }
00336 }

Generated on Fri May 16 08:34:17 2008 for SecondLife by  doxygen 1.5.5