PageRenderTime 205ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llviewerthrottle.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 333 lines | 237 code | 53 blank | 43 comment | 24 complexity | fce0061d70f8fe55b2c175b230744a47 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llviewerthrottle.cpp
  3. * @brief LLViewerThrottle class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llviewerthrottle.h"
  28. #include "llviewercontrol.h"
  29. #include "message.h"
  30. #include "llagent.h"
  31. #include "llframetimer.h"
  32. #include "llviewerstats.h"
  33. #include "lldatapacker.h"
  34. using namespace LLOldEvents;
  35. // consts
  36. // The viewer is allowed to set the under-the-hood bandwidth to 50%
  37. // greater than the prefs UI shows, under the assumption that the
  38. // viewer won't receive all the different message types at once.
  39. // I didn't design this, don't know who did. JC
  40. const F32 MAX_FRACTIONAL = 1.5f;
  41. const F32 MIN_FRACTIONAL = 0.2f;
  42. const F32 MIN_BANDWIDTH = 50.f;
  43. const F32 MAX_BANDWIDTH = 3000.f;
  44. const F32 STEP_FRACTIONAL = 0.1f;
  45. const F32 TIGHTEN_THROTTLE_THRESHOLD = 3.0f; // packet loss % per s
  46. const F32 EASE_THROTTLE_THRESHOLD = 0.5f; // packet loss % per s
  47. const F32 DYNAMIC_UPDATE_DURATION = 5.0f; // seconds
  48. LLViewerThrottle gViewerThrottle;
  49. // static
  50. const std:: string LLViewerThrottle::sNames[TC_EOF] = {
  51. "Resend",
  52. "Land",
  53. "Wind",
  54. "Cloud",
  55. "Task",
  56. "Texture",
  57. "Asset"
  58. };
  59. // Bandwidth settings for different bit rates, they're interpolated/extrapolated.
  60. // Resend Land Wind Cloud Task Texture Asset
  61. const F32 BW_PRESET_50[TC_EOF] = { 5, 10, 3, 3, 10, 10, 9 };
  62. const F32 BW_PRESET_300[TC_EOF] = { 30, 40, 9, 9, 86, 86, 40 };
  63. const F32 BW_PRESET_500[TC_EOF] = { 50, 70, 14, 14, 136, 136, 80 };
  64. const F32 BW_PRESET_1000[TC_EOF] = { 100, 100, 20, 20, 310, 310, 140 };
  65. LLViewerThrottleGroup::LLViewerThrottleGroup()
  66. {
  67. S32 i;
  68. for (i = 0; i < TC_EOF; i++)
  69. {
  70. mThrottles[i] = 0.f;
  71. }
  72. mThrottleTotal = 0.f;
  73. }
  74. LLViewerThrottleGroup::LLViewerThrottleGroup(const F32 settings[])
  75. {
  76. mThrottleTotal = 0.f;
  77. S32 i;
  78. for (i = 0; i < TC_EOF; i++)
  79. {
  80. mThrottles[i] = settings[i];
  81. mThrottleTotal += settings[i];
  82. }
  83. }
  84. LLViewerThrottleGroup LLViewerThrottleGroup::operator*(const F32 frac) const
  85. {
  86. LLViewerThrottleGroup res;
  87. res.mThrottleTotal = 0.f;
  88. S32 i;
  89. for (i = 0; i < TC_EOF; i++)
  90. {
  91. res.mThrottles[i] = mThrottles[i] * frac;
  92. res.mThrottleTotal += res.mThrottles[i];
  93. }
  94. return res;
  95. }
  96. LLViewerThrottleGroup LLViewerThrottleGroup::operator+(const LLViewerThrottleGroup &b) const
  97. {
  98. LLViewerThrottleGroup res;
  99. res.mThrottleTotal = 0.f;
  100. S32 i;
  101. for (i = 0; i < TC_EOF; i++)
  102. {
  103. res.mThrottles[i] = mThrottles[i] + b.mThrottles[i];
  104. res.mThrottleTotal += res.mThrottles[i];
  105. }
  106. return res;
  107. }
  108. LLViewerThrottleGroup LLViewerThrottleGroup::operator-(const LLViewerThrottleGroup &b) const
  109. {
  110. LLViewerThrottleGroup res;
  111. res.mThrottleTotal = 0.f;
  112. S32 i;
  113. for (i = 0; i < TC_EOF; i++)
  114. {
  115. res.mThrottles[i] = mThrottles[i] - b.mThrottles[i];
  116. res.mThrottleTotal += res.mThrottles[i];
  117. }
  118. return res;
  119. }
  120. void LLViewerThrottleGroup::sendToSim() const
  121. {
  122. llinfos << "Sending throttle settings, total BW " << mThrottleTotal << llendl;
  123. LLMessageSystem* msg = gMessageSystem;
  124. msg->newMessageFast(_PREHASH_AgentThrottle);
  125. msg->nextBlockFast(_PREHASH_AgentData);
  126. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  127. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  128. msg->addU32Fast(_PREHASH_CircuitCode, msg->mOurCircuitCode);
  129. msg->nextBlockFast(_PREHASH_Throttle);
  130. msg->addU32Fast(_PREHASH_GenCounter, 0);
  131. // Pack up the throttle data
  132. U8 tmp[64];
  133. LLDataPackerBinaryBuffer dp(tmp, MAX_THROTTLE_SIZE);
  134. S32 i;
  135. for (i = 0; i < TC_EOF; i++)
  136. {
  137. //sim wants BPS, not KBPS
  138. dp.packF32(mThrottles[i] * 1024.0f, "Throttle");
  139. }
  140. S32 len = dp.getCurrentSize();
  141. msg->addBinaryDataFast(_PREHASH_Throttles, tmp, len);
  142. gAgent.sendReliableMessage();
  143. }
  144. void LLViewerThrottleGroup::dump()
  145. {
  146. S32 i;
  147. for (i = 0; i < TC_EOF; i++)
  148. {
  149. LL_DEBUGS("Throttle") << LLViewerThrottle::sNames[i] << ": " << mThrottles[i] << LL_ENDL;
  150. }
  151. LL_DEBUGS("Throttle") << "Total: " << mThrottleTotal << LL_ENDL;
  152. }
  153. class LLBPSListener : public LLSimpleListener
  154. {
  155. public:
  156. virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
  157. {
  158. gViewerThrottle.setMaxBandwidth((F32) event->getValue().asReal()*1024);
  159. return true;
  160. }
  161. };
  162. LLViewerThrottle::LLViewerThrottle() :
  163. mMaxBandwidth(0.f),
  164. mCurrentBandwidth(0.f),
  165. mThrottleFrac(1.f)
  166. {
  167. // Need to be pushed on in bandwidth order
  168. mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_50));
  169. mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_300));
  170. mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_500));
  171. mPresets.push_back(LLViewerThrottleGroup(BW_PRESET_1000));
  172. }
  173. void LLViewerThrottle::setMaxBandwidth(F32 kbits_per_second, BOOL from_event)
  174. {
  175. if (!from_event)
  176. {
  177. gSavedSettings.setF32("ThrottleBandwidthKBPS", kbits_per_second);
  178. }
  179. gViewerThrottle.load();
  180. if (gAgent.getRegion())
  181. {
  182. gViewerThrottle.sendToSim();
  183. }
  184. }
  185. void LLViewerThrottle::load()
  186. {
  187. mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS")*1024;
  188. resetDynamicThrottle();
  189. mCurrent.dump();
  190. }
  191. void LLViewerThrottle::save() const
  192. {
  193. gSavedSettings.setF32("ThrottleBandwidthKBPS", mMaxBandwidth/1024);
  194. }
  195. void LLViewerThrottle::sendToSim() const
  196. {
  197. mCurrent.sendToSim();
  198. }
  199. LLViewerThrottleGroup LLViewerThrottle::getThrottleGroup(const F32 bandwidth_kbps)
  200. {
  201. //Clamp the bandwidth users can set.
  202. F32 set_bandwidth = llclamp(bandwidth_kbps, MIN_BANDWIDTH, MAX_BANDWIDTH);
  203. S32 count = mPresets.size();
  204. S32 i;
  205. for (i = 0; i < count; i++)
  206. {
  207. if (mPresets[i].getTotal() > set_bandwidth)
  208. {
  209. break;
  210. }
  211. }
  212. if (i == 0)
  213. {
  214. // We return the minimum if it's less than the minimum
  215. return mPresets[0];
  216. }
  217. else if (i == count)
  218. {
  219. // Higher than the highest preset, we extrapolate out based on the
  220. // last two presets. This allows us to keep certain throttle channels from
  221. // growing in bandwidth
  222. F32 delta_bw = set_bandwidth - mPresets[count-1].getTotal();
  223. LLViewerThrottleGroup delta_throttle = mPresets[count - 1] - mPresets[count - 2];
  224. F32 delta_total = delta_throttle.getTotal();
  225. F32 delta_frac = delta_bw / delta_total;
  226. delta_throttle = delta_throttle * delta_frac;
  227. return mPresets[count-1] + delta_throttle;
  228. }
  229. else
  230. {
  231. // In between two presets, just interpolate
  232. F32 delta_bw = set_bandwidth - mPresets[i - 1].getTotal();
  233. LLViewerThrottleGroup delta_throttle = mPresets[i] - mPresets[i - 1];
  234. F32 delta_total = delta_throttle.getTotal();
  235. F32 delta_frac = delta_bw / delta_total;
  236. delta_throttle = delta_throttle * delta_frac;
  237. return mPresets[i - 1] + delta_throttle;
  238. }
  239. }
  240. // static
  241. void LLViewerThrottle::resetDynamicThrottle()
  242. {
  243. mThrottleFrac = MAX_FRACTIONAL;
  244. mCurrentBandwidth = mMaxBandwidth*MAX_FRACTIONAL;
  245. mCurrent = getThrottleGroup(mCurrentBandwidth / 1024.0f);
  246. }
  247. void LLViewerThrottle::updateDynamicThrottle()
  248. {
  249. if (mUpdateTimer.getElapsedTimeF32() < DYNAMIC_UPDATE_DURATION)
  250. {
  251. return;
  252. }
  253. mUpdateTimer.reset();
  254. if (LLViewerStats::getInstance()->mPacketsLostPercentStat.getMean() > TIGHTEN_THROTTLE_THRESHOLD)
  255. {
  256. if (mThrottleFrac <= MIN_FRACTIONAL || mCurrentBandwidth / 1024.0f <= MIN_BANDWIDTH)
  257. {
  258. return;
  259. }
  260. mThrottleFrac -= STEP_FRACTIONAL;
  261. mThrottleFrac = llmax(MIN_FRACTIONAL, mThrottleFrac);
  262. mCurrentBandwidth = mMaxBandwidth * mThrottleFrac;
  263. mCurrent = getThrottleGroup(mCurrentBandwidth / 1024.0f);
  264. mCurrent.sendToSim();
  265. llinfos << "Tightening network throttle to " << mCurrentBandwidth << llendl;
  266. }
  267. else if (LLViewerStats::getInstance()->mPacketsLostPercentStat.getMean() <= EASE_THROTTLE_THRESHOLD)
  268. {
  269. if (mThrottleFrac >= MAX_FRACTIONAL || mCurrentBandwidth / 1024.0f >= MAX_BANDWIDTH)
  270. {
  271. return;
  272. }
  273. mThrottleFrac += STEP_FRACTIONAL;
  274. mThrottleFrac = llmin(MAX_FRACTIONAL, mThrottleFrac);
  275. mCurrentBandwidth = mMaxBandwidth * mThrottleFrac;
  276. mCurrent = getThrottleGroup(mCurrentBandwidth/1024.0f);
  277. mCurrent.sendToSim();
  278. llinfos << "Easing network throttle to " << mCurrentBandwidth << llendl;
  279. }
  280. }