/indra/llmessage/llthrottle.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 585 lines · 379 code · 86 blank · 120 comment · 48 complexity · 4c4cc5b1ee5348eae910701a2260462c MD5 · raw file

  1. /**
  2. * @file llthrottle.cpp
  3. * @brief LLThrottle class used for network bandwidth control.
  4. *
  5. * $LicenseInfo:firstyear=2001&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 "linden_common.h"
  27. #include "llthrottle.h"
  28. #include "llmath.h"
  29. #include "lldatapacker.h"
  30. #include "message.h"
  31. LLThrottle::LLThrottle(const F32 rate)
  32. {
  33. mRate = rate;
  34. mAvailable = 0.f;
  35. mLookaheadSecs = 0.25f;
  36. mLastSendTime = LLMessageSystem::getMessageTimeSeconds(TRUE);
  37. }
  38. void LLThrottle::setRate(const F32 rate)
  39. {
  40. // Need to accumulate available bits when adjusting the rate.
  41. mAvailable = getAvailable();
  42. mLastSendTime = LLMessageSystem::getMessageTimeSeconds();
  43. mRate = rate;
  44. }
  45. F32 LLThrottle::getAvailable()
  46. {
  47. // use a temporary bits_available
  48. // since we don't want to change mBitsAvailable every time
  49. F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime);
  50. return mAvailable + (mRate * elapsed_time);
  51. }
  52. BOOL LLThrottle::checkOverflow(const F32 amount)
  53. {
  54. BOOL retval = TRUE;
  55. F32 lookahead_amount = mRate * mLookaheadSecs;
  56. // use a temporary bits_available
  57. // since we don't want to change mBitsAvailable every time
  58. F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime);
  59. F32 amount_available = mAvailable + (mRate * elapsed_time);
  60. if ((amount_available >= lookahead_amount) || (amount_available > amount))
  61. {
  62. // ...enough space to send this message
  63. // Also do if > lookahead so we can use if amount > capped amount.
  64. retval = FALSE;
  65. }
  66. return retval;
  67. }
  68. BOOL LLThrottle::throttleOverflow(const F32 amount)
  69. {
  70. F32 elapsed_time;
  71. F32 lookahead_amount;
  72. BOOL retval = TRUE;
  73. lookahead_amount = mRate * mLookaheadSecs;
  74. F64 mt_sec = LLMessageSystem::getMessageTimeSeconds();
  75. elapsed_time = (F32)(mt_sec - mLastSendTime);
  76. mLastSendTime = mt_sec;
  77. mAvailable += mRate * elapsed_time;
  78. if (mAvailable >= lookahead_amount)
  79. {
  80. // ...channel completely open, so allow send regardless
  81. // of size. This allows sends on very low BPS channels.
  82. mAvailable = lookahead_amount;
  83. retval = FALSE;
  84. }
  85. else if (mAvailable > amount)
  86. {
  87. // ...enough space to send this message
  88. retval = FALSE;
  89. }
  90. // We actually already sent the bits.
  91. mAvailable -= amount;
  92. // What if bitsavailable goes negative?
  93. // That's OK, because it means someone is banging on the channel,
  94. // so we need some time to recover.
  95. return retval;
  96. }
  97. const F32 THROTTLE_LOOKAHEAD_TIME = 1.f; // seconds
  98. // Make sure that we don't set above these
  99. // values, even if the client asks to be set
  100. // higher
  101. // Note that these values are replicated on the
  102. // client side to set max bandwidth throttling there,
  103. // in llviewerthrottle.cpp. These values are the sum
  104. // of the top two tiers of bandwidth there.
  105. F32 gThrottleMaximumBPS[TC_EOF] =
  106. {
  107. 150000.f, // TC_RESEND
  108. 170000.f, // TC_LAND
  109. 34000.f, // TC_WIND
  110. 34000.f, // TC_CLOUD
  111. 446000.f, // TC_TASK
  112. 446000.f, // TC_TEXTURE
  113. 220000.f, // TC_ASSET
  114. };
  115. // Start low until viewer informs us of capability
  116. // Asset and resend get high values, since they
  117. // aren't used JUST by the viewer necessarily.
  118. // This is a HACK and should be dealt with more properly on
  119. // circuit creation.
  120. F32 gThrottleDefaultBPS[TC_EOF] =
  121. {
  122. 100000.f, // TC_RESEND
  123. 4000.f, // TC_LAND
  124. 4000.f, // TC_WIND
  125. 4000.f, // TC_CLOUD
  126. 4000.f, // TC_TASK
  127. 4000.f, // TC_TEXTURE
  128. 100000.f, // TC_ASSET
  129. };
  130. // Don't throttle down lower than this
  131. // This potentially wastes 50 kbps, but usually
  132. // wont.
  133. F32 gThrottleMinimumBPS[TC_EOF] =
  134. {
  135. 10000.f, // TC_RESEND
  136. 10000.f, // TC_LAND
  137. 4000.f, // TC_WIND
  138. 4000.f, // TC_CLOUD
  139. 20000.f, // TC_TASK
  140. 10000.f, // TC_TEXTURE
  141. 10000.f, // TC_ASSET
  142. };
  143. const char* THROTTLE_NAMES[TC_EOF] =
  144. {
  145. "Resend ",
  146. "Land ",
  147. "Wind ",
  148. "Cloud ",
  149. "Task ",
  150. "Texture",
  151. "Asset "
  152. };
  153. LLThrottleGroup::LLThrottleGroup()
  154. {
  155. S32 i;
  156. for (i = 0; i < TC_EOF; i++)
  157. {
  158. mThrottleTotal[i] = gThrottleDefaultBPS[i];
  159. mNominalBPS[i] = gThrottleDefaultBPS[i];
  160. }
  161. resetDynamicAdjust();
  162. }
  163. void LLThrottleGroup::packThrottle(LLDataPacker &dp) const
  164. {
  165. S32 i;
  166. for (i = 0; i < TC_EOF; i++)
  167. {
  168. dp.packF32(mThrottleTotal[i], "Throttle");
  169. }
  170. }
  171. void LLThrottleGroup::unpackThrottle(LLDataPacker &dp)
  172. {
  173. S32 i;
  174. for (i = 0; i < TC_EOF; i++)
  175. {
  176. F32 temp_throttle;
  177. dp.unpackF32(temp_throttle, "Throttle");
  178. temp_throttle = llclamp(temp_throttle, 0.f, 2250000.f);
  179. mThrottleTotal[i] = temp_throttle;
  180. if(mThrottleTotal[i] > gThrottleMaximumBPS[i])
  181. {
  182. mThrottleTotal[i] = gThrottleMaximumBPS[i];
  183. }
  184. }
  185. }
  186. // Call this whenever mNominalBPS changes. Need to reset
  187. // the measurement systems. In the future, we should look
  188. // into NOT resetting the system.
  189. void LLThrottleGroup::resetDynamicAdjust()
  190. {
  191. F64 mt_sec = LLMessageSystem::getMessageTimeSeconds();
  192. S32 i;
  193. for (i = 0; i < TC_EOF; i++)
  194. {
  195. mCurrentBPS[i] = mNominalBPS[i];
  196. mBitsAvailable[i] = mNominalBPS[i] * THROTTLE_LOOKAHEAD_TIME;
  197. mLastSendTime[i] = mt_sec;
  198. mBitsSentThisPeriod[i] = 0;
  199. mBitsSentHistory[i] = 0;
  200. }
  201. mDynamicAdjustTime = mt_sec;
  202. }
  203. BOOL LLThrottleGroup::setNominalBPS(F32* throttle_vec)
  204. {
  205. BOOL changed = FALSE;
  206. S32 i;
  207. for (i = 0; i < TC_EOF; i++)
  208. {
  209. if (mNominalBPS[i] != throttle_vec[i])
  210. {
  211. changed = TRUE;
  212. mNominalBPS[i] = throttle_vec[i];
  213. }
  214. }
  215. // If we changed the nominal settings, reset the dynamic
  216. // adjustment subsystem.
  217. if (changed)
  218. {
  219. resetDynamicAdjust();
  220. }
  221. return changed;
  222. }
  223. // Return bits available in the channel
  224. S32 LLThrottleGroup::getAvailable(S32 throttle_cat)
  225. {
  226. S32 retval = 0;
  227. F32 category_bps = mCurrentBPS[throttle_cat];
  228. F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
  229. // use a temporary bits_available
  230. // since we don't want to change mBitsAvailable every time
  231. F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]);
  232. F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time);
  233. if (bits_available >= lookahead_bits)
  234. {
  235. retval = (S32) gThrottleMaximumBPS[throttle_cat];
  236. }
  237. else
  238. {
  239. retval = (S32) bits_available;
  240. }
  241. return retval;
  242. }
  243. BOOL LLThrottleGroup::checkOverflow(S32 throttle_cat, F32 bits)
  244. {
  245. BOOL retval = TRUE;
  246. F32 category_bps = mCurrentBPS[throttle_cat];
  247. F32 lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
  248. // use a temporary bits_available
  249. // since we don't want to change mBitsAvailable every time
  250. F32 elapsed_time = (F32)(LLMessageSystem::getMessageTimeSeconds() - mLastSendTime[throttle_cat]);
  251. F32 bits_available = mBitsAvailable[throttle_cat] + (category_bps * elapsed_time);
  252. if (bits_available >= lookahead_bits)
  253. {
  254. // ...channel completely open, so allow send regardless
  255. // of size. This allows sends on very low BPS channels.
  256. mBitsAvailable[throttle_cat] = lookahead_bits;
  257. retval = FALSE;
  258. }
  259. else if ( bits_available > bits )
  260. {
  261. // ...enough space to send this message
  262. retval = FALSE;
  263. }
  264. return retval;
  265. }
  266. BOOL LLThrottleGroup::throttleOverflow(S32 throttle_cat, F32 bits)
  267. {
  268. F32 elapsed_time;
  269. F32 category_bps;
  270. F32 lookahead_bits;
  271. BOOL retval = TRUE;
  272. category_bps = mCurrentBPS[throttle_cat];
  273. lookahead_bits = category_bps * THROTTLE_LOOKAHEAD_TIME;
  274. F64 mt_sec = LLMessageSystem::getMessageTimeSeconds();
  275. elapsed_time = (F32)(mt_sec - mLastSendTime[throttle_cat]);
  276. mLastSendTime[throttle_cat] = mt_sec;
  277. mBitsAvailable[throttle_cat] += category_bps * elapsed_time;
  278. if (mBitsAvailable[throttle_cat] >= lookahead_bits)
  279. {
  280. // ...channel completely open, so allow send regardless
  281. // of size. This allows sends on very low BPS channels.
  282. mBitsAvailable[throttle_cat] = lookahead_bits;
  283. retval = FALSE;
  284. }
  285. else if ( mBitsAvailable[throttle_cat] > bits )
  286. {
  287. // ...enough space to send this message
  288. retval = FALSE;
  289. }
  290. // We actually already sent the bits.
  291. mBitsAvailable[throttle_cat] -= bits;
  292. mBitsSentThisPeriod[throttle_cat] += bits;
  293. // What if bitsavailable goes negative?
  294. // That's OK, because it means someone is banging on the channel,
  295. // so we need some time to recover.
  296. return retval;
  297. }
  298. BOOL LLThrottleGroup::dynamicAdjust()
  299. {
  300. const F32 DYNAMIC_ADJUST_TIME = 1.0f; // seconds
  301. const F32 CURRENT_PERIOD_WEIGHT = .25f; // how much weight to give to last period while determining BPS utilization
  302. const F32 BUSY_PERCENT = 0.75f; // if use more than this fraction of BPS, you are busy
  303. const F32 IDLE_PERCENT = 0.70f; // if use less than this fraction, you are "idle"
  304. const F32 TRANSFER_PERCENT = 0.90f; // how much unused bandwidth to take away each adjustment
  305. const F32 RECOVER_PERCENT = 0.25f; // how much to give back during recovery phase
  306. S32 i;
  307. F64 mt_sec = LLMessageSystem::getMessageTimeSeconds();
  308. // Only dynamically adjust every few seconds
  309. if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME)
  310. {
  311. return FALSE;
  312. }
  313. mDynamicAdjustTime = mt_sec;
  314. S32 total = 0;
  315. // Update historical information
  316. for (i = 0; i < TC_EOF; i++)
  317. {
  318. if (mBitsSentHistory[i] == 0)
  319. {
  320. // first run, just copy current period
  321. mBitsSentHistory[i] = mBitsSentThisPeriod[i];
  322. }
  323. else
  324. {
  325. // have some history, so weight accordingly
  326. mBitsSentHistory[i] = (1.f - CURRENT_PERIOD_WEIGHT) * mBitsSentHistory[i]
  327. + CURRENT_PERIOD_WEIGHT * mBitsSentThisPeriod[i];
  328. }
  329. mBitsSentThisPeriod[i] = 0;
  330. total += llround(mBitsSentHistory[i]);
  331. }
  332. // Look for busy channels
  333. // TODO: Fold into loop above.
  334. BOOL channels_busy = FALSE;
  335. F32 busy_nominal_sum = 0;
  336. BOOL channel_busy[TC_EOF];
  337. BOOL channel_idle[TC_EOF];
  338. BOOL channel_over_nominal[TC_EOF];
  339. for (i = 0; i < TC_EOF; i++)
  340. {
  341. // Is this a busy channel?
  342. if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME * mCurrentBPS[i])
  343. {
  344. // this channel is busy
  345. channels_busy = TRUE;
  346. busy_nominal_sum += mNominalBPS[i]; // use for allocation of pooled idle bandwidth
  347. channel_busy[i] = TRUE;
  348. }
  349. else
  350. {
  351. channel_busy[i] = FALSE;
  352. }
  353. // Is this an idle channel?
  354. if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME * mCurrentBPS[i]) &&
  355. (mBitsAvailable[i] > 0))
  356. {
  357. channel_idle[i] = TRUE;
  358. }
  359. else
  360. {
  361. channel_idle[i] = FALSE;
  362. }
  363. // Is this an overpumped channel?
  364. if (mCurrentBPS[i] > mNominalBPS[i])
  365. {
  366. channel_over_nominal[i] = TRUE;
  367. }
  368. else
  369. {
  370. channel_over_nominal[i] = FALSE;
  371. }
  372. //if (total)
  373. //{
  374. // llinfos << i << ": B" << channel_busy[i] << " I" << channel_idle[i] << " N" << channel_over_nominal[i];
  375. // llcont << " Nom: " << mNominalBPS[i] << " Cur: " << mCurrentBPS[i] << " BS: " << mBitsSentHistory[i] << llendl;
  376. //}
  377. }
  378. if (channels_busy)
  379. {
  380. // Some channels are busy. Let's see if we can get them some bandwidth.
  381. F32 used_bps;
  382. F32 avail_bps;
  383. F32 transfer_bps;
  384. F32 pool_bps = 0;
  385. for (i = 0; i < TC_EOF; i++)
  386. {
  387. if (channel_idle[i] || channel_over_nominal[i] )
  388. {
  389. // Either channel i is idle, or has been overpumped.
  390. // Therefore it's a candidate to give up some bandwidth.
  391. // Figure out how much bandwidth it has been using, and how
  392. // much is available to steal.
  393. used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME;
  394. // CRO make sure to keep a minimum amount of throttle available
  395. // CRO NB: channels set to < MINIMUM_BPS will never give up bps,
  396. // which is correct I think
  397. if (used_bps < gThrottleMinimumBPS[i])
  398. {
  399. used_bps = gThrottleMinimumBPS[i];
  400. }
  401. if (channel_over_nominal[i])
  402. {
  403. F32 unused_current = mCurrentBPS[i] - used_bps;
  404. avail_bps = llmax(mCurrentBPS[i] - mNominalBPS[i], unused_current);
  405. }
  406. else
  407. {
  408. avail_bps = mCurrentBPS[i] - used_bps;
  409. }
  410. //llinfos << i << " avail " << avail_bps << llendl;
  411. // Historically, a channel could have used more than its current share,
  412. // even if it's idle right now.
  413. // Make sure we don't steal too much.
  414. if (avail_bps < 0)
  415. {
  416. continue;
  417. }
  418. // Transfer some bandwidth from this channel into the global pool.
  419. transfer_bps = avail_bps * TRANSFER_PERCENT;
  420. mCurrentBPS[i] -= transfer_bps;
  421. pool_bps += transfer_bps;
  422. }
  423. }
  424. //llinfos << "Pool BPS: " << pool_bps << llendl;
  425. // Now redistribute the bandwidth to busy channels.
  426. F32 unused_bps = 0.f;
  427. for (i = 0; i < TC_EOF; i++)
  428. {
  429. if (channel_busy[i])
  430. {
  431. F32 add_amount = pool_bps * (mNominalBPS[i] / busy_nominal_sum);
  432. //llinfos << "Busy " << i << " gets " << pool_bps << llendl;
  433. mCurrentBPS[i] += add_amount;
  434. // CRO: make sure this doesn't get too huge
  435. // JC - Actually, need to let mCurrentBPS go less than nominal, otherwise
  436. // you aren't allowing bandwidth to actually be moved from one channel
  437. // to another.
  438. // *TODO: If clamping high end, would be good to re-
  439. // allocate to other channels in the above code.
  440. const F32 MAX_BPS = 4 * mNominalBPS[i];
  441. if (mCurrentBPS[i] > MAX_BPS)
  442. {
  443. F32 overage = mCurrentBPS[i] - MAX_BPS;
  444. mCurrentBPS[i] -= overage;
  445. unused_bps += overage;
  446. }
  447. // Paranoia
  448. if (mCurrentBPS[i] < gThrottleMinimumBPS[i])
  449. {
  450. mCurrentBPS[i] = gThrottleMinimumBPS[i];
  451. }
  452. }
  453. }
  454. // For fun, add the overage back in to objects
  455. if (unused_bps > 0.f)
  456. {
  457. mCurrentBPS[TC_TASK] += unused_bps;
  458. }
  459. }
  460. else
  461. {
  462. // No one is busy.
  463. // Make the channel allocations seek toward nominal.
  464. // Look for overpumped channels
  465. F32 starved_nominal_sum = 0;
  466. F32 avail_bps = 0;
  467. F32 transfer_bps = 0;
  468. F32 pool_bps = 0;
  469. for (i = 0; i < TC_EOF; i++)
  470. {
  471. if (mCurrentBPS[i] > mNominalBPS[i])
  472. {
  473. avail_bps = (mCurrentBPS[i] - mNominalBPS[i]);
  474. transfer_bps = avail_bps * RECOVER_PERCENT;
  475. mCurrentBPS[i] -= transfer_bps;
  476. pool_bps += transfer_bps;
  477. }
  478. }
  479. // Evenly distribute bandwidth to channels currently
  480. // using less than nominal.
  481. for (i = 0; i < TC_EOF; i++)
  482. {
  483. if (mCurrentBPS[i] < mNominalBPS[i])
  484. {
  485. // We're going to weight allocations by nominal BPS.
  486. starved_nominal_sum += mNominalBPS[i];
  487. }
  488. }
  489. for (i = 0; i < TC_EOF; i++)
  490. {
  491. if (mCurrentBPS[i] < mNominalBPS[i])
  492. {
  493. // Distribute bandwidth according to nominal allocation ratios.
  494. mCurrentBPS[i] += pool_bps * (mNominalBPS[i] / starved_nominal_sum);
  495. }
  496. }
  497. }
  498. return TRUE;
  499. }