llthrottle.cpp 14 KB

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