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
00043
00044
00045
00046
00047
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;
00055 const F32 EASE_THROTTLE_THRESHOLD = 0.5f;
00056 const F32 DYNAMIC_UPDATE_DURATION = 5.0f;
00057
00058 LLViewerThrottle gViewerThrottle;
00059
00060
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
00073
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
00165 U8 tmp[64];
00166 LLDataPackerBinaryBuffer dp(tmp, MAX_THROTTLE_SIZE);
00167 S32 i;
00168 for (i = 0; i < TC_EOF; i++)
00169 {
00170
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 llinfos << LLViewerThrottle::sNames[i] << ": " << mThrottles[i] << llendl;
00186 }
00187 llinfos << "Total: " << mThrottleTotal << llendl;
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
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
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
00266 return mPresets[0];
00267 }
00268 else if (i == count)
00269 {
00270
00271
00272
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
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
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 (gViewerStats->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 (gViewerStats->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 }