llfloaterlagmeter.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /**
  2. * @file llfloaterlagmeter.cpp
  3. * @brief The "Lag-o-Meter" floater used to tell users what is causing lag.
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewergpl$
  6. *
  7. * Copyright (c) 2007-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 "llviewerprecompiledheaders.h"
  33. #include "llfloaterlagmeter.h"
  34. #include "llbutton.h"
  35. #include "lltextbox.h"
  36. #include "lluictrlfactory.h"
  37. #include "llappviewer.h"
  38. #include "lltexturefetch.h"
  39. #include "llviewercontrol.h"
  40. #include "llviewerstats.h"
  41. #include "llviewertexture.h"
  42. // Do not refresh more than twice a second
  43. constexpr F32 REFRESH_INTERVAL = 0.5f;
  44. const std::string LAG_CRITICAL_IMAGE_NAME = "lag_status_critical.tga";
  45. const std::string LAG_WARNING_IMAGE_NAME = "lag_status_warning.tga";
  46. const std::string LAG_GOOD_IMAGE_NAME = "lag_status_good.tga";
  47. LLFloaterLagMeter::LLFloaterLagMeter(const LLSD& key)
  48. : LLFloater("lag meter"),
  49. mShrunk(false)
  50. {
  51. LLUICtrlFactory::getInstance()->buildFloater(this, "floater_lagmeter.xml");
  52. // Don't let this window take keyboard focus -- it's confusing to
  53. // lose arrow-key driving when testing lag.
  54. setIsChrome(true);
  55. mMinimizeButton = getChild<LLButton>("minimize");
  56. mMinimizeButton->setClickedCallback(onClickShrink, this);
  57. mHelpButton = getChild<LLButton>("server_help");
  58. mClientButton = getChild<LLButton>("client_lagmeter");
  59. mClientLabel = getChild<LLTextBox>("client");
  60. mClientText = getChild<LLTextBox>("client_text");
  61. mClientCause = getChild<LLTextBox>("client_lag_cause");
  62. mNetworkButton = getChild<LLButton>("network_lagmeter");
  63. mNetworkLabel = getChild<LLTextBox>("network");
  64. mNetworkText = getChild<LLTextBox>("network_text");
  65. mNetworkCause = getChild<LLTextBox>("network_lag_cause");
  66. mServerButton = getChild<LLButton>("server_lagmeter");
  67. mServerLabel = getChild<LLTextBox>("server");
  68. mServerText = getChild<LLTextBox>("server_text");
  69. mServerCause = getChild<LLTextBox>("server_lag_cause");
  70. std::string config_string = getString("client_frame_rate_critical_fps",
  71. mStringArgs);
  72. mClientFrameTimeCritical = 1.f / (F32)atof(config_string.c_str());
  73. config_string = getString("client_frame_rate_warning_fps", mStringArgs);
  74. mClientFrameTimeWarning = 1.f / (F32)atof(config_string.c_str());
  75. config_string = getString("network_packet_loss_critical_pct", mStringArgs);
  76. mNetworkPacketLossCritical = (F32)atof(config_string.c_str());
  77. config_string = getString("network_packet_loss_warning_pct", mStringArgs);
  78. mNetworkPacketLossWarning = (F32)atof(config_string.c_str());
  79. config_string = getString("network_ping_critical_ms", mStringArgs);
  80. mNetworkPingCritical = (F32)atof(config_string.c_str());
  81. config_string = getString("network_ping_warning_ms", mStringArgs);
  82. mNetworkPingWarning = (F32)atof(config_string.c_str());
  83. config_string = getString("server_frame_rate_critical_fps", mStringArgs);
  84. mServerFrameTimeCritical = 1000.f / (F32)atof(config_string.c_str());
  85. config_string = getString("server_frame_rate_warning_fps", mStringArgs);
  86. mServerFrameTimeWarning = 1000.f / (F32)atof(config_string.c_str());
  87. config_string = getString("server_single_process_max_time_ms",
  88. mStringArgs);
  89. mServerSingleProcessMaxTime = (F32)atof(config_string.c_str());
  90. config_string = getString("max_width_px", mStringArgs);
  91. mMaxWidth = atoi(config_string.c_str());
  92. config_string = getString("min_width_px", mStringArgs);
  93. mMinWidth = atoi(config_string.c_str());
  94. mStringArgs["CLIENT_FRAME_RATE_CRITICAL"] =
  95. getString("client_frame_rate_critical_fps");
  96. mStringArgs["CLIENT_FRAME_RATE_WARNING"] =
  97. getString("client_frame_rate_warning_fps");
  98. mStringArgs["NETWORK_PACKET_LOSS_CRITICAL"] =
  99. getString("network_packet_loss_critical_pct");
  100. mStringArgs["NETWORK_PACKET_LOSS_WARNING"] =
  101. getString("network_packet_loss_warning_pct");
  102. mStringArgs["NETWORK_PING_CRITICAL"] =
  103. getString("network_ping_critical_ms");
  104. mStringArgs["NETWORK_PING_WARNING"] =
  105. getString("network_ping_warning_ms");
  106. mStringArgs["SERVER_FRAME_RATE_CRITICAL"] =
  107. getString("server_frame_rate_critical_fps");
  108. mStringArgs["SERVER_FRAME_RATE_WARNING"] =
  109. getString("server_frame_rate_warning_fps");
  110. // Were we shrunk last time ?
  111. if (gSavedSettings.getBool("LagMeterShrunk"))
  112. {
  113. shrink();
  114. }
  115. }
  116. void LLFloaterLagMeter::onClose(bool app_quitting)
  117. {
  118. // Save the shrunk status for next time
  119. gSavedSettings.setBool("LagMeterShrunk", mShrunk);
  120. // Expand so that we save the proper window rectangle
  121. if (mShrunk)
  122. {
  123. expand();
  124. }
  125. LLFloater::onClose(app_quitting);
  126. }
  127. void LLFloaterLagMeter::draw()
  128. {
  129. if (mUpdateTimer.getElapsedTimeF32() >= REFRESH_INTERVAL)
  130. {
  131. refresh();
  132. mUpdateTimer.reset();
  133. }
  134. LLFloater::draw();
  135. }
  136. void LLFloaterLagMeter::refresh()
  137. {
  138. determineClient();
  139. determineNetwork();
  140. determineServer();
  141. }
  142. void LLFloaterLagMeter::determineClient()
  143. {
  144. F32 client_frame_time = gViewerStats.mFPSStat.getMeanDuration();
  145. if (!gFocusMgr.getAppHasFocus())
  146. {
  147. mClientButton->setImageUnselected(LAG_GOOD_IMAGE_NAME);
  148. mClientText->setText(getString("client_frame_time_window_bg_msg",
  149. mStringArgs));
  150. mClientCause->setText(LLStringUtil::null);
  151. return;
  152. }
  153. else if (client_frame_time >= mClientFrameTimeCritical)
  154. {
  155. mClientButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME);
  156. mClientText->setText(getString("client_frame_time_critical_msg",
  157. mStringArgs));
  158. }
  159. else if (client_frame_time >= mClientFrameTimeWarning)
  160. {
  161. mClientButton->setImageUnselected(LAG_WARNING_IMAGE_NAME);
  162. mClientText->setText(getString("client_frame_time_warning_msg",
  163. mStringArgs));
  164. }
  165. else
  166. {
  167. mClientButton->setImageUnselected(LAG_GOOD_IMAGE_NAME);
  168. mClientText->setText(getString("client_frame_time_normal_msg",
  169. mStringArgs));
  170. mClientCause->setText(LLStringUtil::null);
  171. return;
  172. }
  173. static LLCachedControl<F32> draw_distance(gSavedSettings, "RenderFarClip");
  174. if (draw_distance > 256)
  175. {
  176. mClientCause->setText(getString("client_draw_distance_cause_msg",
  177. mStringArgs));
  178. }
  179. else if (gTextureFetchp->getApproxNumRequests() > 16)
  180. {
  181. mClientCause->setText(getString("client_texture_loading_cause_msg",
  182. mStringArgs));
  183. }
  184. else if (LLViewerTexture::sBoundTexMemoryMB >
  185. LLViewerTexture::sMaxBoundTexMemMB)
  186. {
  187. mClientCause->setText(getString("client_texture_memory_cause_msg",
  188. mStringArgs));
  189. }
  190. else
  191. {
  192. mClientCause->setText(getString("client_complex_objects_cause_msg",
  193. mStringArgs));
  194. }
  195. }
  196. void LLFloaterLagMeter::determineNetwork()
  197. {
  198. F32 packet_loss = gViewerStats.mPacketsLostPercentStat.getMean();
  199. F32 ping_time = gViewerStats.mSimPingStat.getMean();
  200. bool find_cause_loss = false;
  201. bool find_cause_ping = false;
  202. // *FIXME: We cannot blame a large ping time on anything in particular if
  203. // the frame rate is low, because a low frame rate is a sure recipe for
  204. // crappy ping times right now until the network handlers are de-synched
  205. // from the rendering.
  206. F32 frame_time_ms = 1000.f * gViewerStats.mFPSStat.getMeanDuration();
  207. if (packet_loss >= mNetworkPacketLossCritical)
  208. {
  209. mNetworkButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME);
  210. mNetworkText->setText(getString("network_packet_loss_critical_msg",
  211. mStringArgs));
  212. find_cause_loss = true;
  213. }
  214. else if (ping_time >= mNetworkPingCritical)
  215. {
  216. mNetworkButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME);
  217. if (frame_time_ms < mNetworkPingCritical)
  218. {
  219. mNetworkText->setText(getString("network_ping_critical_msg",
  220. mStringArgs));
  221. find_cause_ping = true;
  222. }
  223. }
  224. else if (packet_loss >= mNetworkPacketLossWarning)
  225. {
  226. mNetworkButton->setImageUnselected(LAG_WARNING_IMAGE_NAME);
  227. mNetworkText->setText(getString("network_packet_loss_warning_msg",
  228. mStringArgs));
  229. find_cause_loss = true;
  230. }
  231. else if (ping_time >= mNetworkPingWarning)
  232. {
  233. mNetworkButton->setImageUnselected(LAG_WARNING_IMAGE_NAME);
  234. if (frame_time_ms < mNetworkPingWarning)
  235. {
  236. mNetworkText->setText(getString("network_ping_warning_msg",
  237. mStringArgs));
  238. find_cause_ping = true;
  239. }
  240. }
  241. else
  242. {
  243. mNetworkButton->setImageUnselected(LAG_GOOD_IMAGE_NAME);
  244. mNetworkText->setText(getString("network_performance_normal_msg",
  245. mStringArgs));
  246. }
  247. if (find_cause_loss)
  248. {
  249. mNetworkCause->setText(getString("network_packet_loss_cause_msg",
  250. mStringArgs));
  251. }
  252. else if (find_cause_ping)
  253. {
  254. mNetworkCause->setText(getString("network_ping_cause_msg",
  255. mStringArgs));
  256. }
  257. else
  258. {
  259. mNetworkCause->setText(LLStringUtil::null);
  260. }
  261. }
  262. void LLFloaterLagMeter::determineServer()
  263. {
  264. F32 sim_frame_time = gViewerStats.mSimFrameMsec.getCurrent();
  265. if (sim_frame_time >= mServerFrameTimeCritical)
  266. {
  267. mServerButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME);
  268. mServerText->setText(getString("server_frame_time_critical_msg",
  269. mStringArgs));
  270. }
  271. else if (sim_frame_time >= mServerFrameTimeWarning)
  272. {
  273. mServerButton->setImageUnselected(LAG_WARNING_IMAGE_NAME);
  274. mServerText->setText(getString("server_frame_time_warning_msg",
  275. mStringArgs));
  276. }
  277. else
  278. {
  279. mServerButton->setImageUnselected(LAG_GOOD_IMAGE_NAME);
  280. mServerText->setText(getString("server_frame_time_normal_msg",
  281. mStringArgs));
  282. mServerCause->setText(LLStringUtil::null);
  283. return;
  284. }
  285. if (gViewerStats.mSimSimPhysicsMsec.getCurrent() > mServerSingleProcessMaxTime)
  286. {
  287. mServerCause->setText(getString("server_physics_cause_msg",
  288. mStringArgs));
  289. return;
  290. }
  291. if (gViewerStats.mSimScriptMsec.getCurrent() > mServerSingleProcessMaxTime)
  292. {
  293. mServerCause->setText(getString("server_scripts_cause_msg",
  294. mStringArgs));
  295. return;
  296. }
  297. if (gViewerStats.mSimNetMsec.getCurrent() > mServerSingleProcessMaxTime)
  298. {
  299. mServerCause->setText(getString("server_net_cause_msg",
  300. mStringArgs));
  301. return;
  302. }
  303. if (gViewerStats.mSimAgentMsec.getCurrent() > mServerSingleProcessMaxTime)
  304. {
  305. mServerCause->setText(getString("server_agent_cause_msg",
  306. mStringArgs));
  307. return;
  308. }
  309. if (gViewerStats.mSimImagesMsec.getCurrent() > mServerSingleProcessMaxTime)
  310. {
  311. mServerCause->setText(getString("server_images_cause_msg",
  312. mStringArgs));
  313. return;
  314. }
  315. mServerCause->setText(getString("server_generic_cause_msg", mStringArgs));
  316. }
  317. void LLFloaterLagMeter::expand()
  318. {
  319. setTitle(getString("max_title_msg", mStringArgs));
  320. // Make left edge appear to expand
  321. S32 delta_width = mMaxWidth - mMinWidth;
  322. LLRect r = getRect();
  323. r.translate(-delta_width, 0);
  324. setRect(r);
  325. reshape(mMaxWidth, getRect().getHeight());
  326. std::string text = getString("client_text_msg", mStringArgs) + ":";
  327. mClientLabel->setText(text);
  328. text = getString("network_text_msg", mStringArgs) + ":";
  329. mNetworkLabel->setText(text);
  330. text = getString("server_text_msg", mStringArgs) + ":";
  331. mServerLabel->setValue(text);
  332. // Usually "<<"
  333. mMinimizeButton->setLabel(getString("smaller_label", mStringArgs));
  334. mMinimizeButton->setFocus(false);
  335. mClientText->setVisible(true);
  336. mClientCause->setVisible(true);
  337. mNetworkText->setVisible(true);
  338. mNetworkCause->setVisible(true);
  339. mServerText->setVisible(true);
  340. mServerCause->setVisible(true);
  341. mHelpButton->setVisible(true);
  342. mShrunk = false;
  343. }
  344. void LLFloaterLagMeter::shrink()
  345. {
  346. setTitle(getString("min_title_msg", mStringArgs));
  347. // make left edge appear to collapse
  348. S32 delta_width = mMaxWidth - mMinWidth;
  349. LLRect r = getRect();
  350. r.translate(delta_width, 0);
  351. setRect(r);
  352. reshape(mMinWidth, getRect().getHeight());
  353. mClientLabel->setValue(LLSD(getString("client_text_msg", mStringArgs)));
  354. mNetworkLabel->setValue(LLSD(getString("network_text_msg", mStringArgs)));
  355. mServerLabel->setValue(LLSD(getString("server_text_msg", mStringArgs)));
  356. // usually ">>"
  357. mMinimizeButton->setLabel(getString("bigger_label", mStringArgs));
  358. mMinimizeButton->setFocus(false);
  359. mClientText->setVisible(false);
  360. mClientCause->setVisible(false);
  361. mNetworkText->setVisible(false);
  362. mNetworkCause->setVisible(false);
  363. mServerText->setVisible(false);
  364. mServerCause->setVisible(false);
  365. mHelpButton->setVisible(false);
  366. mShrunk = true;
  367. }
  368. //static
  369. void LLFloaterLagMeter::onClickShrink(void* data)
  370. {
  371. LLFloaterLagMeter* self = (LLFloaterLagMeter*)data;
  372. if (!self) return;
  373. if (self->mShrunk)
  374. {
  375. self->expand();
  376. }
  377. else
  378. {
  379. self->shrink();
  380. }
  381. }