llfasttimerview.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:31k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llfasttimerview.cpp
  3.  * @brief LLFastTimerView class implementation
  4.  *
  5.  * $LicenseInfo:firstyear=2004&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2004-2010, 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 "llfasttimerview.h"
  34. #include "llviewerwindow.h"
  35. #include "llrect.h"
  36. #include "llerror.h"
  37. #include "llgl.h"
  38. #include "llrender.h"
  39. #include "lllocalcliprect.h"
  40. #include "llmath.h"
  41. #include "llfontgl.h"
  42. #include "llsdserialize.h"
  43. #include "lltooltip.h"
  44. #include "llappviewer.h"
  45. #include "llviewertexturelist.h"
  46. #include "llui.h"
  47. #include "llviewercontrol.h"
  48. #include "llstat.h"
  49. #include "llfasttimer.h"
  50. #include "lltreeiterators.h"
  51. #include "llmetricperformancetester.h"
  52. //////////////////////////////////////////////////////////////////////////////
  53. static const S32 MAX_VISIBLE_HISTORY = 10;
  54. static const S32 LINE_GRAPH_HEIGHT = 240;
  55. //static const int FTV_DISPLAY_NUM  = (sizeof(ft_display_table)/sizeof(ft_display_table[0]));
  56. static S32 FTV_NUM_TIMERS;
  57. const S32 FTV_MAX_DEPTH = 8;
  58. std::vector<LLFastTimer::NamedTimer*> ft_display_idx; // line of table entry for display purposes (for collapse)
  59. typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_iterator_t;
  60. BOOL LLFastTimerView::sAnalyzePerformance = FALSE;
  61. static timer_tree_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) 
  62. return timer_tree_iterator_t(&id, 
  63. boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), 
  64. boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
  65. }
  66. static timer_tree_iterator_t end_timer_tree() 
  67. return timer_tree_iterator_t(); 
  68. }
  69. LLFastTimerView::LLFastTimerView(const LLRect& rect)
  70. : LLFloater(LLSD()),
  71. mHoverTimer(NULL)
  72. {
  73. setRect(rect);
  74. setVisible(FALSE);
  75. mDisplayMode = 0;
  76. mAvgCountTotal = 0;
  77. mMaxCountTotal = 0;
  78. mDisplayCenter = ALIGN_CENTER;
  79. mDisplayCalls = 0;
  80. mDisplayHz = 0;
  81. mScrollIndex = 0;
  82. mHoverID = NULL;
  83. mHoverBarIndex = -1;
  84. FTV_NUM_TIMERS = LLFastTimer::NamedTimer::instanceCount();
  85. mPrintStats = -1;
  86. mAverageCyclesPerTimer = 0;
  87. }
  88. BOOL LLFastTimerView::handleRightMouseDown(S32 x, S32 y, MASK mask)
  89. {
  90. if (mHoverTimer )
  91. {
  92. // right click collapses timers
  93. if (!mHoverTimer->getCollapsed())
  94. {
  95. mHoverTimer->setCollapsed(true);
  96. }
  97. else if (mHoverTimer->getParent())
  98. {
  99. mHoverTimer->getParent()->setCollapsed(true);
  100. }
  101. }
  102. else if (mBarRect.pointInRect(x, y))
  103. {
  104. S32 bar_idx = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight());
  105. bar_idx = llclamp(bar_idx, 0, MAX_VISIBLE_HISTORY);
  106. mPrintStats = bar_idx;
  107. }
  108. return FALSE;
  109. }
  110. LLFastTimer::NamedTimer* LLFastTimerView::getLegendID(S32 y)
  111. {
  112. S32 idx = (getRect().getHeight() - y) / ((S32) LLFontGL::getFontMonospace()->getLineHeight()+2) - 5;
  113. if (idx >= 0 && idx < (S32)ft_display_idx.size())
  114. {
  115. return ft_display_idx[idx];
  116. }
  117. return NULL;
  118. }
  119. BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask)
  120. {
  121. if (x < mBarRect.mLeft) 
  122. {
  123. LLFastTimer::NamedTimer* idp = getLegendID(y);
  124. if (idp)
  125. {
  126. idp->setCollapsed(!idp->getCollapsed());
  127. }
  128. }
  129. else if (mHoverTimer)
  130. {
  131. //left click drills down by expanding timers
  132. mHoverTimer->setCollapsed(false);
  133. }
  134. else if (mask & MASK_ALT)
  135. {
  136. if (mask & MASK_CONTROL)
  137. {
  138. mDisplayHz = !mDisplayHz;
  139. }
  140. else
  141. {
  142. mDisplayCalls = !mDisplayCalls;
  143. }
  144. }
  145. else if (mask & MASK_SHIFT)
  146. {
  147. if (++mDisplayMode > 3)
  148. mDisplayMode = 0;
  149. }
  150. else if (mask & MASK_CONTROL)
  151. {
  152. mDisplayCenter = (ChildAlignment)((mDisplayCenter + 1) % ALIGN_COUNT);
  153. }
  154. else
  155. {
  156. // pause/unpause
  157. LLFastTimer::sPauseHistory = !LLFastTimer::sPauseHistory;
  158. // reset scroll to bottom when unpausing
  159. if (!LLFastTimer::sPauseHistory)
  160. {
  161. mScrollIndex = 0;
  162. }
  163. }
  164. // SJB: Don't pass mouse clicks through the display
  165. return TRUE;
  166. }
  167. BOOL LLFastTimerView::handleMouseUp(S32 x, S32 y, MASK mask)
  168. {
  169. return FALSE;
  170. }
  171. BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
  172. {
  173. mHoverTimer = NULL;
  174. mHoverID = NULL;
  175. if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y))
  176. {
  177. mHoverBarIndex = llmin(LLFastTimer::getCurFrameIndex() - 1, 
  178. MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()));
  179. if (mHoverBarIndex == 0)
  180. {
  181. return TRUE;
  182. }
  183. else if (mHoverBarIndex == -1)
  184. {
  185. mHoverBarIndex = 0;
  186. }
  187. S32 i = 0;
  188. for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer());
  189. it != end_timer_tree();
  190. ++it, ++i)
  191. {
  192. // is mouse over bar for this timer?
  193. if (x > mBarStart[mHoverBarIndex][i] &&
  194. x < mBarEnd[mHoverBarIndex][i])
  195. {
  196. mHoverID = (*it);
  197. mHoverTimer = (*it);
  198. mToolTipRect.set(mBarStart[mHoverBarIndex][i], 
  199. mBarRect.mBottom + llround(((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex + 1)) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f))),
  200. mBarEnd[mHoverBarIndex][i],
  201. mBarRect.mBottom + llround((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f))));
  202. }
  203. if ((*it)->getCollapsed())
  204. {
  205. it.skipDescendants();
  206. }
  207. }
  208. }
  209. else if (x < mBarRect.mLeft) 
  210. {
  211. LLFastTimer::NamedTimer* timer_id = getLegendID(y);
  212. if (timer_id)
  213. {
  214. mHoverID = timer_id;
  215. }
  216. }
  217. return FALSE;
  218. }
  219. BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask)
  220. {
  221. if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y))
  222. {
  223. // tooltips for timer bars
  224. if (mHoverTimer)
  225. {
  226. LLRect screen_rect;
  227. localRectToScreen(mToolTipRect, &screen_rect);
  228. LLToolTipMgr::instance().show(LLToolTip::Params()
  229. .message(mHoverTimer->getToolTip(LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex))
  230. .sticky_rect(screen_rect)
  231. .delay_time(0.f));
  232. return TRUE;
  233. }
  234. }
  235. else
  236. {
  237. // tooltips for timer legend
  238. if (x < mBarRect.mLeft) 
  239. {
  240. LLFastTimer::NamedTimer* idp = getLegendID(y);
  241. if (idp)
  242. {
  243. LLToolTipMgr::instance().show(idp->getToolTip());
  244. return TRUE;
  245. }
  246. }
  247. }
  248. return FALSE;
  249. }
  250. BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks)
  251. {
  252. LLFastTimer::sPauseHistory = TRUE;
  253. mScrollIndex = llclamp(mScrollIndex - clicks, 
  254. 0, 
  255. llmin(LLFastTimer::getLastFrameIndex(), (S32)LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY));
  256. return TRUE;
  257. }
  258. static LLFastTimer::DeclareTimer FTM_RENDER_TIMER("Timers", true);
  259. static std::map<LLFastTimer::NamedTimer*, LLColor4> sTimerColors;
  260. void LLFastTimerView::draw()
  261. {
  262. LLFastTimer t(FTM_RENDER_TIMER);
  263. std::string tdesc;
  264. F64 clock_freq = (F64)LLFastTimer::countsPerSecond();
  265. F64 iclock_freq = 1000.0 / clock_freq;
  266. S32 margin = 10;
  267. S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.75f);
  268. S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f);
  269. LLRect new_rect;
  270. new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
  271. setRect(new_rect);
  272. S32 left, top, right, bottom;
  273. S32 x, y, barw, barh, dx, dy;
  274. S32 texth, textw;
  275. LLPointer<LLUIImage> box_imagep = LLUI::getUIImage("Rounded_Square");
  276. // Draw the window background
  277. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  278. gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
  279. S32 xleft = margin;
  280. S32 ytop = margin;
  281. mAverageCyclesPerTimer = LLFastTimer::sTimerCalls == 0 
  282. ? 0 
  283. : llround(lerp((F32)mAverageCyclesPerTimer, (F32)(LLFastTimer::sTimerCycles / (U64)LLFastTimer::sTimerCalls), 0.1f));
  284. LLFastTimer::sTimerCycles = 0;
  285. LLFastTimer::sTimerCalls = 0;
  286. // Draw some help
  287. {
  288. x = xleft;
  289. y = height - ytop;
  290. texth = (S32)LLFontGL::getFontMonospace()->getLineHeight();
  291. #if TIME_FAST_TIMERS
  292. tdesc = llformat("Cycles per timer call: %d", mAverageCyclesPerTimer);
  293. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
  294. #else
  295. char modedesc[][32] = {
  296. "2 x Average ",
  297. "Max         ",
  298. "Recent Max  ",
  299. "100 ms      "
  300. };
  301. char centerdesc[][32] = {
  302. "Left      ",
  303. "Centered  ",
  304. "Ordered   "
  305. };
  306. tdesc = llformat("Full bar = %s [Click to pause/reset] [SHIFT-Click to toggle]",modedesc[mDisplayMode]);
  307. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
  308. textw = LLFontGL::getFontMonospace()->getWidth(tdesc);
  309. x = xleft, y -= (texth + 2);
  310. tdesc = llformat("Justification = %s [CTRL-Click to toggle]",centerdesc[mDisplayCenter]);
  311. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
  312. y -= (texth + 2);
  313. LLFontGL::getFontMonospace()->renderUTF8(std::string("[Right-Click log selected] [ALT-Click toggle counts] [ALT-SHIFT-Click sub hidden]"),
  314.  0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
  315. #endif
  316. y -= (texth + 2);
  317. }
  318. S32 histmax = llmin(LLFastTimer::getLastFrameIndex()+1, MAX_VISIBLE_HISTORY);
  319. // Draw the legend
  320. xleft = margin;
  321. ytop = y;
  322. y -= (texth + 2);
  323. sTimerColors[&LLFastTimer::NamedTimer::getRootNamedTimer()] = LLColor4::grey;
  324. F32 hue = 0.f;
  325. for (timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer());
  326. it != timer_tree_iterator_t();
  327. ++it)
  328. {
  329. LLFastTimer::NamedTimer* idp = (*it);
  330. const F32 HUE_INCREMENT = 0.23f;
  331. hue = fmodf(hue + HUE_INCREMENT, 1.f);
  332. // saturation increases with depth
  333. F32 saturation = clamp_rescale((F32)idp->getDepth(), 0.f, 3.f, 0.f, 1.f);
  334. // lightness alternates with depth
  335. F32 lightness = idp->getDepth() % 2 ? 0.5f : 0.6f;
  336. LLColor4 child_color;
  337. child_color.setHSL(hue, saturation, lightness);
  338. sTimerColors[idp] = child_color;
  339. }
  340. const S32 LEGEND_WIDTH = 220;
  341. {
  342. LLLocalClipRect clip(LLRect(margin, y, LEGEND_WIDTH, margin));
  343. S32 cur_line = 0;
  344. ft_display_idx.clear();
  345. std::map<LLFastTimer::NamedTimer*, S32> display_line;
  346. for (timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer());
  347. it != timer_tree_iterator_t();
  348. ++it)
  349. {
  350. LLFastTimer::NamedTimer* idp = (*it);
  351. display_line[idp] = cur_line;
  352. ft_display_idx.push_back(idp);
  353. cur_line++;
  354. x = xleft;
  355. left = x; right = x + texth;
  356. top = y; bottom = y - texth;
  357. S32 scale_offset = 0;
  358. if (idp == mHoverID)
  359. {
  360. scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 2.f);
  361. }
  362. gl_rect_2d(left - scale_offset, top + scale_offset, right + scale_offset, bottom - scale_offset, sTimerColors[idp]);
  363. F32 ms = 0;
  364. S32 calls = 0;
  365. if (mHoverBarIndex > 0 && mHoverID)
  366. {
  367. S32 hidx = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex;
  368. U64 ticks = idp->getHistoricalCount(hidx);
  369. ms = (F32)((F64)ticks * iclock_freq);
  370. calls = (S32)idp->getHistoricalCalls(hidx);
  371. }
  372. else
  373. {
  374. U64 ticks = idp->getCountAverage();
  375. ms = (F32)((F64)ticks * iclock_freq);
  376. calls = (S32)idp->getCallAverage();
  377. }
  378. if (mDisplayCalls)
  379. {
  380. tdesc = llformat("%s (%d)",idp->getName().c_str(),calls);
  381. }
  382. else
  383. {
  384. tdesc = llformat("%s [%.1f]",idp->getName().c_str(),ms);
  385. }
  386. dx = (texth+4) + idp->getDepth()*8;
  387. LLColor4 color = LLColor4::white;
  388. if (idp->getDepth() > 0)
  389. {
  390. S32 line_start_y = (top + bottom) / 2;
  391. S32 line_end_y = line_start_y + ((texth + 2) * (cur_line - display_line[idp->getParent()])) - texth;
  392. gl_line_2d(x + dx - 8, line_start_y, x + dx, line_start_y, color);
  393. S32 line_x = x + (texth + 4) + ((idp->getDepth() - 1) * 8);
  394. gl_line_2d(line_x, line_start_y, line_x, line_end_y, color);
  395. if (idp->getCollapsed() && !idp->getChildren().empty())
  396. {
  397. gl_line_2d(line_x+4, line_start_y-3, line_x+4, line_start_y+4, color);
  398. }
  399. }
  400. x += dx;
  401. BOOL is_child_of_hover_item = (idp == mHoverID);
  402. LLFastTimer::NamedTimer* next_parent = idp->getParent();
  403. while(!is_child_of_hover_item && next_parent)
  404. {
  405. is_child_of_hover_item = (mHoverID == next_parent);
  406. next_parent = next_parent->getParent();
  407. }
  408. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, 
  409. x, y, 
  410. color, 
  411. LLFontGL::LEFT, LLFontGL::TOP, 
  412. is_child_of_hover_item ? LLFontGL::BOLD : LLFontGL::NORMAL);
  413. y -= (texth + 2);
  414. textw = dx + LLFontGL::getFontMonospace()->getWidth(idp->getName()) + 40;
  415. if (idp->getCollapsed()) 
  416. {
  417. it.skipDescendants();
  418. }
  419. }
  420. }
  421. xleft += LEGEND_WIDTH + 8;
  422. // ytop = ytop;
  423. // update rectangle that includes timer bars
  424. mBarRect.mLeft = xleft;
  425. mBarRect.mRight = getRect().getWidth();
  426. mBarRect.mTop = ytop - ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4);
  427. mBarRect.mBottom = margin + LINE_GRAPH_HEIGHT;
  428. y = ytop;
  429. barh = (ytop - margin - LINE_GRAPH_HEIGHT) / (MAX_VISIBLE_HISTORY + 2);
  430. dy = barh>>2; // spacing between bars
  431. if (dy < 1) dy = 1;
  432. barh -= dy;
  433. barw = width - xleft - margin;
  434. // Draw the history bars
  435. if (LLFastTimer::getLastFrameIndex() >= 0)
  436. {
  437. LLLocalClipRect clip(LLRect(xleft, ytop, getRect().getWidth() - margin, margin));
  438. U64 totalticks;
  439. if (!LLFastTimer::sPauseHistory)
  440. {
  441. U64 ticks = LLFastTimer::NamedTimer::getRootNamedTimer().getHistoricalCount(mScrollIndex);
  442. if (LLFastTimer::getCurFrameIndex() >= 10)
  443. {
  444. U64 framec = LLFastTimer::getCurFrameIndex();
  445. U64 avg = (U64)mAvgCountTotal;
  446. mAvgCountTotal = (avg*framec + ticks) / (framec + 1);
  447. if (ticks > mMaxCountTotal)
  448. {
  449. mMaxCountTotal = ticks;
  450. }
  451. }
  452. if (ticks < mAvgCountTotal/100 || ticks > mAvgCountTotal*100)
  453. {
  454. LLFastTimer::sResetHistory = true;
  455. }
  456. if (LLFastTimer::getCurFrameIndex() < 10 || LLFastTimer::sResetHistory)
  457. {
  458. mAvgCountTotal = ticks;
  459. mMaxCountTotal = ticks;
  460. }
  461. }
  462. if (mDisplayMode == 0)
  463. {
  464. totalticks = mAvgCountTotal*2;
  465. }
  466. else if (mDisplayMode == 1)
  467. {
  468. totalticks = mMaxCountTotal;
  469. }
  470. else if (mDisplayMode == 2)
  471. {
  472. // Calculate the max total ticks for the current history
  473. totalticks = 0;
  474. for (S32 j=0; j<histmax; j++)
  475. {
  476. U64 ticks = LLFastTimer::NamedTimer::getRootNamedTimer().getHistoricalCount(j);
  477. if (ticks > totalticks)
  478. totalticks = ticks;
  479. }
  480. }
  481. else
  482. {
  483. totalticks = (U64)(clock_freq * .1); // 100 ms
  484. }
  485. // Draw MS ticks
  486. {
  487. U32 ms = (U32)((F64)totalticks * iclock_freq) ;
  488. tdesc = llformat("%.1f ms |", (F32)ms*.25f);
  489. x = xleft + barw/4 - LLFontGL::getFontMonospace()->getWidth(tdesc);
  490. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
  491.  LLFontGL::LEFT, LLFontGL::TOP);
  492. tdesc = llformat("%.1f ms |", (F32)ms*.50f);
  493. x = xleft + barw/2 - LLFontGL::getFontMonospace()->getWidth(tdesc);
  494. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
  495.  LLFontGL::LEFT, LLFontGL::TOP);
  496. tdesc = llformat("%.1f ms |", (F32)ms*.75f);
  497. x = xleft + (barw*3)/4 - LLFontGL::getFontMonospace()->getWidth(tdesc);
  498. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
  499.  LLFontGL::LEFT, LLFontGL::TOP);
  500. tdesc = llformat( "%d ms |", ms);
  501. x = xleft + barw - LLFontGL::getFontMonospace()->getWidth(tdesc);
  502. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
  503.  LLFontGL::LEFT, LLFontGL::TOP);
  504. }
  505. LLRect graph_rect;
  506. // Draw borders
  507. {
  508. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  509. gGL.color4f(0.5f,0.5f,0.5f,0.5f);
  510. S32 by = y + 2;
  511. y -= ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4);
  512. //heading
  513. gl_rect_2d(xleft-5, by, getRect().getWidth()-5, y+5, FALSE);
  514. //tree view
  515. gl_rect_2d(5, by, xleft-10, 5, FALSE);
  516. by = y + 5;
  517. //average bar
  518. gl_rect_2d(xleft-5, by, getRect().getWidth()-5, by-barh-dy-5, FALSE);
  519. by -= barh*2+dy;
  520. //current frame bar
  521. gl_rect_2d(xleft-5, by, getRect().getWidth()-5, by-barh-dy-2, FALSE);
  522. by -= barh+dy+1;
  523. //history bars
  524. gl_rect_2d(xleft-5, by, getRect().getWidth()-5, LINE_GRAPH_HEIGHT-barh-dy-2, FALSE);
  525. by = LINE_GRAPH_HEIGHT-barh-dy-7;
  526. //line graph
  527. graph_rect = LLRect(xleft-5, by, getRect().getWidth()-5, 5);
  528. gl_rect_2d(graph_rect, FALSE);
  529. }
  530. mBarStart.clear();
  531. mBarEnd.clear();
  532. // Draw bars for each history entry
  533. // Special: -1 = show running average
  534. gGL.getTexUnit(0)->bind(box_imagep->getImage());
  535. for (S32 j=-1; j<histmax && y > LINE_GRAPH_HEIGHT; j++)
  536. {
  537. mBarStart.push_back(std::vector<S32>());
  538. mBarEnd.push_back(std::vector<S32>());
  539. int sublevel_dx[FTV_MAX_DEPTH];
  540. int sublevel_left[FTV_MAX_DEPTH];
  541. int sublevel_right[FTV_MAX_DEPTH];
  542. S32 tidx;
  543. if (j >= 0)
  544. {
  545. tidx = LLFastTimer::NamedTimer::HISTORY_NUM - j - 1 - mScrollIndex;
  546. }
  547. else
  548. {
  549. tidx = -1;
  550. }
  551. x = xleft;
  552. // draw the bars for each stat
  553. std::vector<S32> xpos;
  554. std::vector<S32> deltax;
  555. xpos.push_back(xleft);
  556. LLFastTimer::NamedTimer* prev_id = NULL;
  557. S32 i = 0;
  558. for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer());
  559. it != end_timer_tree();
  560. ++it, ++i)
  561. {
  562. LLFastTimer::NamedTimer* idp = (*it);
  563. F32 frac = tidx == -1
  564. ? (F32)idp->getCountAverage() / (F32)totalticks 
  565. : (F32)idp->getHistoricalCount(tidx) / (F32)totalticks;
  566. dx = llround(frac * (F32)barw);
  567. S32 prev_delta_x = deltax.empty() ? 0 : deltax.back();
  568. deltax.push_back(dx);
  569. int level = idp->getDepth() - 1;
  570. while ((S32)xpos.size() > level + 1)
  571. {
  572. xpos.pop_back();
  573. }
  574. left = xpos.back();
  575. if (level == 0)
  576. {
  577. sublevel_left[level] = xleft;
  578. sublevel_dx[level] = dx;
  579. sublevel_right[level] = sublevel_left[level] + sublevel_dx[level];
  580. }
  581. else if (prev_id && prev_id->getDepth() < idp->getDepth())
  582. {
  583. U64 sublevelticks = 0;
  584. for (LLFastTimer::NamedTimer::child_const_iter it = prev_id->beginChildren();
  585. it != prev_id->endChildren();
  586. ++it)
  587. {
  588. sublevelticks += (tidx == -1)
  589. ? (*it)->getCountAverage() 
  590. : (*it)->getHistoricalCount(tidx);
  591. }
  592. F32 subfrac = (F32)sublevelticks / (F32)totalticks;
  593. sublevel_dx[level] = (int)(subfrac * (F32)barw + .5f);
  594. if (mDisplayCenter == ALIGN_CENTER)
  595. {
  596. left += (prev_delta_x - sublevel_dx[level])/2;
  597. }
  598. else if (mDisplayCenter == ALIGN_RIGHT)
  599. {
  600. left += (prev_delta_x - sublevel_dx[level]);
  601. }
  602. sublevel_left[level] = left;
  603. sublevel_right[level] = sublevel_left[level] + sublevel_dx[level];
  604. }
  605. right = left + dx;
  606. xpos.back() = right;
  607. xpos.push_back(left);
  608. mBarStart.back().push_back(left);
  609. mBarEnd.back().push_back(right);
  610. top = y;
  611. bottom = y - barh;
  612. if (right > left)
  613. {
  614. //U32 rounded_edges = 0;
  615. LLColor4 color = sTimerColors[idp];//*ft_display_table[i].color;
  616. S32 scale_offset = 0;
  617. BOOL is_child_of_hover_item = (idp == mHoverID);
  618. LLFastTimer::NamedTimer* next_parent = idp->getParent();
  619. while(!is_child_of_hover_item && next_parent)
  620. {
  621. is_child_of_hover_item = (mHoverID == next_parent);
  622. next_parent = next_parent->getParent();
  623. }
  624. if (idp == mHoverID)
  625. {
  626. scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 3.f);
  627. //color = lerp(color, LLColor4::black, -0.4f);
  628. }
  629. else if (mHoverID != NULL && !is_child_of_hover_item)
  630. {
  631. color = lerp(color, LLColor4::grey, 0.8f);
  632. }
  633. gGL.color4fv(color.mV);
  634. F32 start_fragment = llclamp((F32)(left - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
  635. F32 end_fragment = llclamp((F32)(right - sublevel_left[level]) / (F32)sublevel_dx[level], 0.f, 1.f);
  636. gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment);
  637. }
  638. if ((*it)->getCollapsed())
  639. {
  640. it.skipDescendants();
  641. }
  642. prev_id = idp;
  643. }
  644. y -= (barh + dy);
  645. if (j < 0)
  646. y -= barh;
  647. }
  648. //draw line graph history
  649. {
  650. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  651. LLLocalClipRect clip(graph_rect);
  652. //normalize based on last frame's maximum
  653. static U64 last_max = 0;
  654. static F32 alpha_interp = 0.f;
  655. U64 max_ticks = llmax(last_max, (U64) 1);
  656. F32 ms = (F32)((F64)max_ticks * iclock_freq);
  657. //display y-axis range
  658. std::string tdesc;
  659.  if (mDisplayCalls)
  660. tdesc = llformat("%d calls", (int)max_ticks);
  661. else if (mDisplayHz)
  662. tdesc = llformat("%d Hz", (int)max_ticks);
  663. else
  664. tdesc = llformat("%4.2f ms", ms);
  665. x = graph_rect.mRight - LLFontGL::getFontMonospace()->getWidth(tdesc)-5;
  666. y = graph_rect.mTop - ((S32)LLFontGL::getFontMonospace()->getLineHeight());
  667.  
  668. LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, LLColor4::white,
  669.  LLFontGL::LEFT, LLFontGL::TOP);
  670. //highlight visible range
  671. {
  672. S32 first_frame = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex;
  673. S32 last_frame = first_frame - MAX_VISIBLE_HISTORY;
  674. F32 frame_delta = ((F32) (graph_rect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1);
  675. F32 right = (F32) graph_rect.mLeft + frame_delta*first_frame;
  676. F32 left = (F32) graph_rect.mLeft + frame_delta*last_frame;
  677. gGL.color4f(0.5f,0.5f,0.5f,0.3f);
  678. gl_rect_2d((S32) left, graph_rect.mTop, (S32) right, graph_rect.mBottom);
  679. if (mHoverBarIndex >= 0)
  680. {
  681. S32 bar_frame = first_frame - mHoverBarIndex;
  682. F32 bar = (F32) graph_rect.mLeft + frame_delta*bar_frame;
  683. gGL.color4f(0.5f,0.5f,0.5f,1);
  684. gGL.begin(LLRender::LINES);
  685. gGL.vertex2i((S32)bar, graph_rect.mBottom);
  686. gGL.vertex2i((S32)bar, graph_rect.mTop);
  687. gGL.end();
  688. }
  689. }
  690. U64 cur_max = 0;
  691. for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer());
  692. it != end_timer_tree();
  693. ++it)
  694. {
  695. LLFastTimer::NamedTimer* idp = (*it);
  696. //fatten highlighted timer
  697. if (mHoverID == idp)
  698. {
  699. gGL.flush();
  700. glLineWidth(3);
  701. }
  702. const F32 * col = sTimerColors[idp].mV;// ft_display_table[idx].color->mV;
  703. F32 alpha = 1.f;
  704. if (mHoverID != NULL &&
  705. idp != mHoverID)
  706. { //fade out non-hihglighted timers
  707. if (idp->getParent() != mHoverID)
  708. {
  709. alpha = alpha_interp;
  710. }
  711. }
  712. gGL.color4f(col[0], col[1], col[2], alpha);
  713. gGL.begin(LLRender::LINE_STRIP);
  714. for (U32 j = 0; j < LLFastTimer::NamedTimer::HISTORY_NUM; j++)
  715. {
  716. U64 ticks = idp->getHistoricalCount(j);
  717. if (mDisplayHz)
  718. {
  719. F64 tc = (F64) (ticks+1) * iclock_freq;
  720. tc = 1000.f/tc;
  721. ticks = llmin((U64) tc, (U64) 1024);
  722. }
  723. else if (mDisplayCalls)
  724. {
  725. ticks = (S32)idp->getHistoricalCalls(j);
  726. }
  727. if (alpha == 1.f)
  728. //normalize to highlighted timer
  729. cur_max = llmax(cur_max, ticks);
  730. }
  731. F32 x = graph_rect.mLeft + ((F32) (graph_rect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1)*j;
  732. F32 y = graph_rect.mBottom + (F32) graph_rect.getHeight()/max_ticks*ticks;
  733. gGL.vertex2f(x,y);
  734. }
  735. gGL.end();
  736. if (mHoverID == idp)
  737. {
  738. gGL.flush();
  739. glLineWidth(1);
  740. }
  741. if (idp->getCollapsed())
  742. {
  743. //skip hidden timers
  744. it.skipDescendants();
  745. }
  746. }
  747. //interpolate towards new maximum
  748. F32 dt = gFrameIntervalSeconds*3.f;
  749. last_max = (U64) ((F32) last_max + ((F32) cur_max- (F32) last_max) * dt);
  750. F32 alpha_target = last_max > cur_max ?
  751. llmin((F32) last_max/ (F32) cur_max - 1.f,1.f) :
  752. llmin((F32) cur_max/ (F32) last_max - 1.f,1.f);
  753. alpha_interp = alpha_interp + (alpha_target-alpha_interp) * dt;
  754. if (mHoverID != NULL)
  755. {
  756. x = (graph_rect.mRight + graph_rect.mLeft)/2;
  757. y = graph_rect.mBottom + 8;
  758. LLFontGL::getFontMonospace()->renderUTF8(
  759. mHoverID->getName(), 
  760. 0, 
  761. x, y, 
  762. LLColor4::white,
  763. LLFontGL::LEFT, LLFontGL::BOTTOM);
  764. }
  765. }
  766. }
  767. // Output stats for clicked bar to log
  768. if (mPrintStats >= 0)
  769. {
  770. std::string legend_stat;
  771. bool first = true;
  772. for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer());
  773. it != end_timer_tree();
  774. ++it)
  775. {
  776. LLFastTimer::NamedTimer* idp = (*it);
  777. if (!first)
  778. {
  779. legend_stat += ", ";
  780. }
  781. first = true;
  782. legend_stat += idp->getName();
  783. if (idp->getCollapsed())
  784. {
  785. it.skipDescendants();
  786. }
  787. }
  788. llinfos << legend_stat << llendl;
  789. std::string timer_stat;
  790. first = true;
  791. for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer());
  792. it != end_timer_tree();
  793. ++it)
  794. {
  795. LLFastTimer::NamedTimer* idp = (*it);
  796. if (!first)
  797. {
  798. timer_stat += ", ";
  799. }
  800. first = false;
  801. U64 ticks;
  802. if (mPrintStats > 0)
  803. {
  804. S32 hidx = (mPrintStats - 1) - mScrollIndex;
  805. ticks = idp->getHistoricalCount(hidx);
  806. }
  807. else
  808. {
  809. ticks = idp->getCountAverage();
  810. }
  811. F32 ms = (F32)((F64)ticks * iclock_freq);
  812. timer_stat += llformat("%.1f",ms);
  813. if (idp->getCollapsed())
  814. {
  815. it.skipDescendants();
  816. }
  817. }
  818. llinfos << timer_stat << llendl;
  819. mPrintStats = -1;
  820. }
  821. mHoverID = NULL;
  822. mHoverBarIndex = -1;
  823. LLView::draw();
  824. }
  825. F64 LLFastTimerView::getTime(const std::string& name)
  826. {
  827. const LLFastTimer::NamedTimer* timerp = LLFastTimer::getTimerByName(name);
  828. if (timerp)
  829. {
  830. return (F64)timerp->getCountAverage() / (F64)LLFastTimer::countsPerSecond();
  831. }
  832. return 0.0;
  833. }
  834. //static
  835. LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is)
  836. {
  837. LLSD ret;
  838. LLSD cur;
  839. LLSD::Real total_time = 0.0;
  840. LLSD::Integer total_frames = 0;
  841. while (!is.eof() && LLSDSerialize::fromXML(cur, is))
  842. {
  843. for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
  844. {
  845. std::string label = iter->first;
  846. F64 time = iter->second["Time"].asReal();
  847. // Skip the total figure
  848. if(label.compare("Total") != 0)
  849. {
  850. total_time += time;
  851. }
  852. if (time > 0.0)
  853. {
  854. ret[label]["TotalTime"] = ret[label]["TotalTime"].asReal() + time;
  855. ret[label]["MaxTime"] = llmax(time, ret[label]["MaxTime"].asReal());
  856. if (ret[label]["MinTime"].asReal() == 0)
  857. {
  858. ret[label]["MinTime"] = time;
  859. }
  860. else
  861. {
  862. ret[label]["MinTime"] = llmin(ret[label]["MinTime"].asReal(), time);
  863. }
  864. LLSD::Integer samples = iter->second["Calls"].asInteger();
  865. ret[label]["Samples"] = ret[label]["Samples"].asInteger() + samples;
  866. ret[label]["MaxSamples"] = llmax(ret[label]["MaxSamples"].asInteger(), samples);
  867. if (ret[label]["MinSamples"].asInteger() == 0)
  868. {
  869. ret[label]["MinSamples"] = samples;
  870. }
  871. else
  872. {
  873. ret[label]["MinSamples"] = llmin(ret[label]["MinSamples"].asInteger(), samples);
  874. }
  875. }
  876. }
  877. total_frames++;
  878. }
  879. ret["SessionTime"] = total_time;
  880. ret["FrameCount"] = total_frames;
  881. return ret;
  882. }
  883. //static
  884. void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target, std::string output)
  885. {
  886. //analyze baseline
  887. std::ifstream base_is(baseline.c_str());
  888. LLSD base = analyzePerformanceLogDefault(base_is);
  889. base_is.close();
  890. //analyze current
  891. std::ifstream target_is(target.c_str());
  892. LLSD current = analyzePerformanceLogDefault(target_is);
  893. target_is.close();
  894. //output comparision
  895. std::ofstream os(output.c_str());
  896. LLSD::Real session_time = current["SessionTime"].asReal();
  897. os << "Label, % Change, % of Session, Cur Min, Cur Max, Cur Mean, Cur Total, Cur Samples, Base Min, Base Max, Base Mean, Base Total, Base Samplesn"; 
  898. for (LLSD::map_iterator iter = base.beginMap();  iter != base.endMap(); ++iter)
  899. {
  900. LLSD::String label = iter->first;
  901. if (current[label]["Samples"].asInteger() == 0 ||
  902. base[label]["Samples"].asInteger() == 0)
  903. {
  904. //cannot compare
  905. continue;
  906. }
  907. LLSD::Real a = base[label]["TotalTime"].asReal() / base[label]["Samples"].asReal();
  908. LLSD::Real b = current[label]["TotalTime"].asReal() / base[label]["Samples"].asReal();
  909. LLSD::Real diff = b-a;
  910. LLSD::Real perc = diff/a * 100;
  911. os << llformat("%s, %.2f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %.4f, %.4f, %.4f, %.4f, %dn",
  912. label.c_str(), 
  913. (F32) perc, 
  914. (F32) (current[label]["TotalTime"].asReal()/session_time * 100.0), 
  915. (F32) current[label]["MinTime"].asReal(), 
  916. (F32) current[label]["MaxTime"].asReal(), 
  917. (F32) b, 
  918. (F32) current[label]["TotalTime"].asReal(), 
  919. current[label]["Samples"].asInteger(),
  920. (F32) base[label]["MinTime"].asReal(), 
  921. (F32) base[label]["MaxTime"].asReal(), 
  922. (F32) a, 
  923. (F32) base[label]["TotalTime"].asReal(), 
  924. base[label]["Samples"].asInteger());
  925. }
  926. os.flush();
  927. os.close();
  928. }
  929. //-------------------------
  930. //static
  931. LLSD LLFastTimerView::analyzeMetricPerformanceLog(std::istream& is)
  932. {
  933. LLSD ret;
  934. LLSD cur;
  935. while (!is.eof() && LLSDSerialize::fromXML(cur, is))
  936. {
  937. for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter)
  938. {
  939. std::string label = iter->first;
  940. LLMetricPerformanceTester* tester = LLMetricPerformanceTester::getTester(iter->second["Name"].asString()) ;
  941. if(tester)
  942. {
  943. ret[label]["Name"] = iter->second["Name"] ;
  944. S32 num_of_strings = tester->getNumOfMetricStrings() ;
  945. for(S32 index = 0 ; index < num_of_strings ; index++)
  946. {
  947. ret[label][ tester->getMetricString(index) ] = iter->second[ tester->getMetricString(index) ] ;
  948. }
  949. }
  950. }
  951. }
  952. return ret;
  953. }
  954. //static
  955. void LLFastTimerView::doAnalysisMetrics(std::string baseline, std::string target, std::string output)
  956. {
  957. if(!LLMetricPerformanceTester::hasMetricPerformanceTesters())
  958. {
  959. return ;
  960. }
  961. //analyze baseline
  962. std::ifstream base_is(baseline.c_str());
  963. LLSD base = analyzeMetricPerformanceLog(base_is);
  964. base_is.close();
  965. //analyze current
  966. std::ifstream target_is(target.c_str());
  967. LLSD current = analyzeMetricPerformanceLog(target_is);
  968. target_is.close();
  969. //output comparision
  970. std::ofstream os(output.c_str());
  971. os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)n"; 
  972. for(LLMetricPerformanceTester::name_tester_map_t::iterator iter = LLMetricPerformanceTester::sTesterMap.begin() ; 
  973. iter != LLMetricPerformanceTester::sTesterMap.end() ; ++iter)
  974. {
  975. LLMetricPerformanceTester* tester = ((LLMetricPerformanceTester*)iter->second) ;
  976. tester->analyzePerformance(&os, &base, &current) ;
  977. }
  978. os.flush();
  979. os.close();
  980. }
  981. //static
  982. void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::string output)
  983. {
  984. if(LLFastTimer::sLog)
  985. {
  986. doAnalysisDefault(baseline, target, output) ;
  987. return ;
  988. }
  989. if(LLFastTimer::sMetricLog)
  990. {
  991. doAnalysisMetrics(baseline, target, output) ;
  992. return ;
  993. }
  994. }