PageRenderTime 716ms CodeModel.GetById 310ms RepoModel.GetById 12ms app.codeStats 2ms

/indra/llcommon/llstat.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1306 lines | 1031 code | 185 blank | 90 comment | 164 complexity | 9a02005714c71f45511f669373c78bfe MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llstat.cpp
  3. *
  4. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "linden_common.h"
  26. #include "llstat.h"
  27. #include "lllivefile.h"
  28. #include "llerrorcontrol.h"
  29. #include "llframetimer.h"
  30. #include "timing.h"
  31. #include "llsd.h"
  32. #include "llsdserialize.h"
  33. #include "llstl.h"
  34. #include "u64.h"
  35. // statics
  36. S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
  37. LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
  38. std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
  39. LLStat::stat_map_t LLStat::sStatList;
  40. //------------------------------------------------------------------------
  41. // Live config file to trigger stats logging
  42. static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd";
  43. static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds
  44. class LLStatsConfigFile : public LLLiveFile
  45. {
  46. public:
  47. LLStatsConfigFile()
  48. : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE),
  49. mChanged(false), mStatsp(NULL) { }
  50. static std::string filename();
  51. protected:
  52. /* virtual */ bool loadFile();
  53. public:
  54. void init(LLPerfStats* statsp);
  55. static LLStatsConfigFile& instance();
  56. // return the singleton stats config file
  57. bool mChanged;
  58. protected:
  59. LLPerfStats* mStatsp;
  60. };
  61. std::string LLStatsConfigFile::filename()
  62. {
  63. return STATS_CONFIG_FILE_NAME;
  64. }
  65. void LLStatsConfigFile::init(LLPerfStats* statsp)
  66. {
  67. mStatsp = statsp;
  68. }
  69. LLStatsConfigFile& LLStatsConfigFile::instance()
  70. {
  71. static LLStatsConfigFile the_file;
  72. return the_file;
  73. }
  74. /* virtual */
  75. // Load and parse the stats configuration file
  76. bool LLStatsConfigFile::loadFile()
  77. {
  78. if (!mStatsp)
  79. {
  80. llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
  81. return false;
  82. }
  83. mChanged = true;
  84. LLSD stats_config;
  85. {
  86. llifstream file(filename().c_str());
  87. if (file.is_open())
  88. {
  89. LLSDSerialize::fromXML(stats_config, file);
  90. if (stats_config.isUndefined())
  91. {
  92. llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
  93. mStatsp->setReportPerformanceDuration( 0.f );
  94. return false;
  95. }
  96. }
  97. else
  98. { // File went away, turn off stats if it was on
  99. if ( mStatsp->frameStatsIsRunning() )
  100. {
  101. llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
  102. mStatsp->setReportPerformanceDuration( 0.f );
  103. }
  104. return true;
  105. }
  106. }
  107. F32 duration = 0.f;
  108. F32 interval = 0.f;
  109. S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
  110. const char * w = "duration";
  111. if (stats_config.has(w))
  112. {
  113. duration = (F32)stats_config[w].asReal();
  114. }
  115. w = "interval";
  116. if (stats_config.has(w))
  117. {
  118. interval = (F32)stats_config[w].asReal();
  119. }
  120. w = "flags";
  121. if (stats_config.has(w))
  122. {
  123. flags = (S32)stats_config[w].asInteger();
  124. if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
  125. duration > 0)
  126. { // No flags passed in, but have a duration, so reset to basic stats
  127. flags = LLPerfBlock::LLSTATS_BASIC_STATS;
  128. }
  129. }
  130. mStatsp->setReportPerformanceDuration( duration, flags );
  131. mStatsp->setReportPerformanceInterval( interval );
  132. if ( duration > 0 )
  133. {
  134. if ( interval == 0.f )
  135. {
  136. llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl;
  137. }
  138. else
  139. {
  140. llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl;
  141. }
  142. }
  143. else
  144. {
  145. llinfos << "Performance stats recording turned off" << llendl;
  146. }
  147. return true;
  148. }
  149. //------------------------------------------------------------------------
  150. LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) :
  151. mFrameStatsFileFailure(FALSE),
  152. mSkipFirstFrameStats(FALSE),
  153. mProcessName(process_name),
  154. mProcessPID(process_pid),
  155. mReportPerformanceStatInterval(1.f),
  156. mReportPerformanceStatEnd(0.0)
  157. { }
  158. LLPerfStats::~LLPerfStats()
  159. {
  160. LLPerfBlock::clearDynamicStats();
  161. mFrameStatsFile.close();
  162. }
  163. void LLPerfStats::init()
  164. {
  165. // Initialize the stats config file instance.
  166. (void) LLStatsConfigFile::instance().init(this);
  167. (void) LLStatsConfigFile::instance().checkAndReload();
  168. }
  169. // Open file for statistics
  170. void LLPerfStats::openPerfStatsFile()
  171. {
  172. if ( !mFrameStatsFile
  173. && !mFrameStatsFileFailure )
  174. {
  175. std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID);
  176. mFrameStatsFile.close();
  177. mFrameStatsFile.clear();
  178. mFrameStatsFile.open(stats_file, llofstream::out);
  179. if ( mFrameStatsFile.fail() )
  180. {
  181. llinfos << "Error opening statistics log file " << stats_file << llendl;
  182. mFrameStatsFileFailure = TRUE;
  183. }
  184. else
  185. {
  186. LLSD process_info = LLSD::emptyMap();
  187. process_info["name"] = mProcessName;
  188. process_info["pid"] = (LLSD::Integer) mProcessPID;
  189. process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval;
  190. // Add process-specific info.
  191. addProcessHeaderInfo(process_info);
  192. mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl;
  193. }
  194. }
  195. }
  196. // Dump out performance metrics over some time interval
  197. void LLPerfStats::dumpIntervalPerformanceStats()
  198. {
  199. // Ensure output file is OK
  200. openPerfStatsFile();
  201. if ( mFrameStatsFile )
  202. {
  203. LLSD stats = LLSD::emptyMap();
  204. LLStatAccum::TimeScale scale;
  205. if ( getReportPerformanceInterval() == 0.f )
  206. {
  207. scale = LLStatAccum::SCALE_PER_FRAME;
  208. }
  209. else if ( getReportPerformanceInterval() < 0.5f )
  210. {
  211. scale = LLStatAccum::SCALE_100MS;
  212. }
  213. else
  214. {
  215. scale = LLStatAccum::SCALE_SECOND;
  216. }
  217. // Write LLSD into log
  218. stats["utc_time"] = (LLSD::String) LLError::utcTime();
  219. stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch
  220. stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount();
  221. // Add process-specific frame info.
  222. addProcessFrameInfo(stats, scale);
  223. LLPerfBlock::addStatsToLLSDandReset( stats, scale );
  224. mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl;
  225. }
  226. }
  227. // Set length of performance stat recording.
  228. // If turning stats on, caller must provide flags
  229. void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
  230. {
  231. if ( seconds <= 0.f )
  232. {
  233. mReportPerformanceStatEnd = 0.0;
  234. LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
  235. mFrameStatsFile.close();
  236. LLPerfBlock::clearDynamicStats();
  237. }
  238. else
  239. {
  240. mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
  241. // Clear failure flag to try and create the log file once
  242. mFrameStatsFileFailure = FALSE;
  243. mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
  244. LLPerfBlock::setStatsFlags(flags);
  245. }
  246. }
  247. void LLPerfStats::updatePerFrameStats()
  248. {
  249. (void) LLStatsConfigFile::instance().checkAndReload();
  250. static LLFrameTimer performance_stats_timer;
  251. if ( frameStatsIsRunning() )
  252. {
  253. if ( mReportPerformanceStatInterval == 0 )
  254. { // Record info every frame
  255. if ( mSkipFirstFrameStats )
  256. { // Skip the first time - was started this frame
  257. mSkipFirstFrameStats = FALSE;
  258. }
  259. else
  260. {
  261. dumpIntervalPerformanceStats();
  262. }
  263. }
  264. else
  265. {
  266. performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() );
  267. if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval ))
  268. {
  269. dumpIntervalPerformanceStats();
  270. }
  271. }
  272. if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd )
  273. { // Reached end of time, clear it to stop reporting
  274. setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly
  275. llinfos << "Recording performance stats completed" << llendl;
  276. }
  277. }
  278. }
  279. //------------------------------------------------------------------------
  280. U64 LLStatAccum::sScaleTimes[NUM_SCALES] =
  281. {
  282. USEC_PER_SEC / 10, // 100 millisec
  283. USEC_PER_SEC * 1, // seconds
  284. USEC_PER_SEC * 60, // minutes
  285. #if ENABLE_LONG_TIME_STATS
  286. // enable these when more time scales are desired
  287. USEC_PER_SEC * 60*60, // hours
  288. USEC_PER_SEC * 24*60*60, // days
  289. USEC_PER_SEC * 7*24*60*60, // weeks
  290. #endif
  291. };
  292. LLStatAccum::LLStatAccum(bool useFrameTimer)
  293. : mUseFrameTimer(useFrameTimer),
  294. mRunning(FALSE),
  295. mLastTime(0),
  296. mLastSampleValue(0.0),
  297. mLastSampleValid(FALSE)
  298. {
  299. }
  300. LLStatAccum::~LLStatAccum()
  301. {
  302. }
  303. void LLStatAccum::reset(U64 when)
  304. {
  305. mRunning = TRUE;
  306. mLastTime = when;
  307. for (int i = 0; i < NUM_SCALES; ++i)
  308. {
  309. mBuckets[i].accum = 0.0;
  310. mBuckets[i].endTime = when + sScaleTimes[i];
  311. mBuckets[i].lastValid = false;
  312. }
  313. }
  314. void LLStatAccum::sum(F64 value)
  315. {
  316. sum(value, getCurrentUsecs());
  317. }
  318. void LLStatAccum::sum(F64 value, U64 when)
  319. {
  320. if (!mRunning)
  321. {
  322. reset(when);
  323. return;
  324. }
  325. if (when < mLastTime)
  326. {
  327. // This happens a LOT on some dual core systems.
  328. lldebugs << "LLStatAccum::sum clock has gone backwards from "
  329. << mLastTime << " to " << when << ", resetting" << llendl;
  330. reset(when);
  331. return;
  332. }
  333. // how long is this value for
  334. U64 timeSpan = when - mLastTime;
  335. for (int i = 0; i < NUM_SCALES; ++i)
  336. {
  337. Bucket& bucket = mBuckets[i];
  338. if (when < bucket.endTime)
  339. {
  340. bucket.accum += value;
  341. }
  342. else
  343. {
  344. U64 timeScale = sScaleTimes[i];
  345. U64 timeLeft = when - bucket.endTime;
  346. // how much time is left after filling this bucket
  347. if (timeLeft < timeScale)
  348. {
  349. F64 valueLeft = value * timeLeft / timeSpan;
  350. bucket.lastValid = true;
  351. bucket.lastAccum = bucket.accum + (value - valueLeft);
  352. bucket.accum = valueLeft;
  353. bucket.endTime += timeScale;
  354. }
  355. else
  356. {
  357. U64 timeTail = timeLeft % timeScale;
  358. bucket.lastValid = true;
  359. bucket.lastAccum = value * timeScale / timeSpan;
  360. bucket.accum = value * timeTail / timeSpan;
  361. bucket.endTime += (timeLeft - timeTail) + timeScale;
  362. }
  363. }
  364. }
  365. mLastTime = when;
  366. }
  367. F32 LLStatAccum::meanValue(TimeScale scale) const
  368. {
  369. if (!mRunning)
  370. {
  371. return 0.0;
  372. }
  373. if ( scale == SCALE_PER_FRAME )
  374. { // Per-frame not supported here
  375. scale = SCALE_100MS;
  376. }
  377. if (scale < 0 || scale >= NUM_SCALES)
  378. {
  379. llwarns << "llStatAccum::meanValue called for unsupported scale: "
  380. << scale << llendl;
  381. return 0.0;
  382. }
  383. const Bucket& bucket = mBuckets[scale];
  384. F64 value = bucket.accum;
  385. U64 timeLeft = bucket.endTime - mLastTime;
  386. U64 scaleTime = sScaleTimes[scale];
  387. if (bucket.lastValid)
  388. {
  389. value += bucket.lastAccum * timeLeft / scaleTime;
  390. }
  391. else if (timeLeft < scaleTime)
  392. {
  393. value *= scaleTime / (scaleTime - timeLeft);
  394. }
  395. else
  396. {
  397. value = 0.0;
  398. }
  399. return (F32)(value / scaleTime);
  400. }
  401. U64 LLStatAccum::getCurrentUsecs() const
  402. {
  403. if (mUseFrameTimer)
  404. {
  405. return LLFrameTimer::getTotalTime();
  406. }
  407. else
  408. {
  409. return totalTime();
  410. }
  411. }
  412. // ------------------------------------------------------------------------
  413. LLStatRate::LLStatRate(bool use_frame_timer)
  414. : LLStatAccum(use_frame_timer)
  415. {
  416. }
  417. void LLStatRate::count(U32 value)
  418. {
  419. sum((F64)value * sScaleTimes[SCALE_SECOND]);
  420. }
  421. void LLStatRate::mark()
  422. {
  423. // Effectively the same as count(1), but sets mLastSampleValue
  424. U64 when = getCurrentUsecs();
  425. if ( mRunning
  426. && (when > mLastTime) )
  427. { // Set mLastSampleValue to the time from the last mark()
  428. F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND];
  429. if ( duration > 0.0 )
  430. {
  431. mLastSampleValue = 1.0 / duration;
  432. }
  433. else
  434. {
  435. mLastSampleValue = 0.0;
  436. }
  437. }
  438. sum( (F64) sScaleTimes[SCALE_SECOND], when);
  439. }
  440. // ------------------------------------------------------------------------
  441. LLStatMeasure::LLStatMeasure(bool use_frame_timer)
  442. : LLStatAccum(use_frame_timer)
  443. {
  444. }
  445. void LLStatMeasure::sample(F64 value)
  446. {
  447. U64 when = getCurrentUsecs();
  448. if (mLastSampleValid)
  449. {
  450. F64 avgValue = (value + mLastSampleValue) / 2.0;
  451. F64 interval = (F64)(when - mLastTime);
  452. sum(avgValue * interval, when);
  453. }
  454. else
  455. {
  456. reset(when);
  457. }
  458. mLastSampleValid = TRUE;
  459. mLastSampleValue = value;
  460. }
  461. // ------------------------------------------------------------------------
  462. LLStatTime::LLStatTime(const std::string & key)
  463. : LLStatAccum(false),
  464. mFrameNumber(LLFrameTimer::getFrameCount()),
  465. mTotalTimeInFrame(0),
  466. mKey(key)
  467. #if LL_DEBUG
  468. , mRunning(FALSE)
  469. #endif
  470. {
  471. }
  472. void LLStatTime::start()
  473. {
  474. // Reset frame accumluation if the frame number has changed
  475. U32 frame_number = LLFrameTimer::getFrameCount();
  476. if ( frame_number != mFrameNumber )
  477. {
  478. mFrameNumber = frame_number;
  479. mTotalTimeInFrame = 0;
  480. }
  481. sum(0.0);
  482. #if LL_DEBUG
  483. // Shouldn't be running already
  484. llassert( !mRunning );
  485. mRunning = TRUE;
  486. #endif
  487. }
  488. void LLStatTime::stop()
  489. {
  490. U64 end_time = getCurrentUsecs();
  491. U64 duration = end_time - mLastTime;
  492. sum(F64(duration), end_time);
  493. //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl;
  494. mTotalTimeInFrame += duration;
  495. #if LL_DEBUG
  496. mRunning = FALSE;
  497. #endif
  498. }
  499. /* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const
  500. {
  501. if ( LLStatAccum::SCALE_PER_FRAME == scale )
  502. {
  503. return mTotalTimeInFrame;
  504. }
  505. else
  506. {
  507. return LLStatAccum::meanValue(scale);
  508. }
  509. }
  510. // ------------------------------------------------------------------------
  511. // Use this constructor for pre-defined LLStatTime objects
  512. LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL)
  513. {
  514. if (mPredefinedStat)
  515. {
  516. // If dynamic stats are turned on, this will create a separate entry in the stat map.
  517. initDynamicStat(mPredefinedStat->mKey);
  518. // Start predefined stats. These stats are not part of the stat map.
  519. mPredefinedStat->start();
  520. }
  521. }
  522. // Use this constructor for normal, optional LLPerfBlock time slices
  523. LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
  524. {
  525. if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
  526. { // These are off unless the base set is enabled
  527. return;
  528. }
  529. initDynamicStat(key);
  530. }
  531. // Use this constructor for dynamically created LLPerfBlock time slices
  532. // that are only enabled by specific control flags
  533. LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
  534. {
  535. if ((sStatsFlags & flags) == 0)
  536. {
  537. return;
  538. }
  539. if (NULL == key2 || strlen(key2) == 0)
  540. {
  541. initDynamicStat(key1);
  542. }
  543. else
  544. {
  545. std::ostringstream key;
  546. key << key1 << "_" << key2;
  547. initDynamicStat(key.str());
  548. }
  549. }
  550. // Set up the result data map if dynamic stats are enabled
  551. void LLPerfBlock::initDynamicStat(const std::string& key)
  552. {
  553. // Early exit if dynamic stats aren't enabled.
  554. if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
  555. return;
  556. mLastPath = sCurrentStatPath; // Save and restore current path
  557. sCurrentStatPath += "/" + key; // Add key to current path
  558. // See if the LLStatTime object already exists
  559. stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath);
  560. if ( iter == sStatMap.end() )
  561. {
  562. // StatEntry object doesn't exist, so create it
  563. mDynamicStat = new StatEntry( key );
  564. sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path
  565. }
  566. else
  567. {
  568. // Found this path in the map, use the object there
  569. mDynamicStat = (*iter).second; // Get StatEntry for the current path
  570. }
  571. if (mDynamicStat)
  572. {
  573. mDynamicStat->mStat.start();
  574. mDynamicStat->mCount++;
  575. }
  576. else
  577. {
  578. llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl;
  579. sCurrentStatPath = mLastPath;
  580. }
  581. }
  582. // Destructor does the time accounting
  583. LLPerfBlock::~LLPerfBlock()
  584. {
  585. if (mPredefinedStat) mPredefinedStat->stop();
  586. if (mDynamicStat)
  587. {
  588. mDynamicStat->mStat.stop();
  589. sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block
  590. }
  591. }
  592. // Clear the map of any dynamic stats. Static routine
  593. void LLPerfBlock::clearDynamicStats()
  594. {
  595. std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer());
  596. sStatMap.clear();
  597. }
  598. // static - Extract the stat info into LLSD
  599. void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
  600. LLStatAccum::TimeScale scale )
  601. {
  602. // If we aren't in per-frame scale, we need to go from second to microsecond.
  603. U32 scale_adjustment = 1;
  604. if (LLStatAccum::SCALE_PER_FRAME != scale)
  605. {
  606. scale_adjustment = USEC_PER_SEC;
  607. }
  608. stat_map_t::iterator iter = sStatMap.begin();
  609. for ( ; iter != sStatMap.end(); ++iter )
  610. { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time
  611. const std::string & stats_full_path = (*iter).first;
  612. StatEntry * stat = (*iter).second;
  613. if (stat)
  614. {
  615. if (stat->mCount > 0)
  616. {
  617. stats[stats_full_path] = LLSD::emptyMap();
  618. stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale));
  619. if (stat->mCount > 1)
  620. {
  621. stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount;
  622. }
  623. stat->mCount = 0;
  624. }
  625. }
  626. else
  627. { // Shouldn't have a NULL pointer in the map.
  628. llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
  629. }
  630. }
  631. }
  632. // ------------------------------------------------------------------------
  633. LLTimer LLStat::sTimer;
  634. LLFrameTimer LLStat::sFrameTimer;
  635. void LLStat::init()
  636. {
  637. llassert(mNumBins > 0);
  638. mNumValues = 0;
  639. mLastValue = 0.f;
  640. mLastTime = 0.f;
  641. mCurBin = (mNumBins-1);
  642. mNextBin = 0;
  643. mBins = new F32[mNumBins];
  644. mBeginTime = new F64[mNumBins];
  645. mTime = new F64[mNumBins];
  646. mDT = new F32[mNumBins];
  647. for (U32 i = 0; i < mNumBins; i++)
  648. {
  649. mBins[i] = 0.f;
  650. mBeginTime[i] = 0.0;
  651. mTime[i] = 0.0;
  652. mDT[i] = 0.f;
  653. }
  654. if (!mName.empty())
  655. {
  656. stat_map_t::iterator iter = sStatList.find(mName);
  657. if (iter != sStatList.end())
  658. llwarns << "LLStat with duplicate name: " << mName << llendl;
  659. sStatList.insert(std::make_pair(mName, this));
  660. }
  661. }
  662. LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
  663. : mUseFrameTimer(use_frame_timer),
  664. mNumBins(num_bins)
  665. {
  666. init();
  667. }
  668. LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
  669. : mUseFrameTimer(use_frame_timer),
  670. mNumBins(num_bins),
  671. mName(name)
  672. {
  673. init();
  674. }
  675. LLStat::~LLStat()
  676. {
  677. delete[] mBins;
  678. delete[] mBeginTime;
  679. delete[] mTime;
  680. delete[] mDT;
  681. if (!mName.empty())
  682. {
  683. // handle multiple entries with the same name
  684. stat_map_t::iterator iter = sStatList.find(mName);
  685. while (iter != sStatList.end() && iter->second != this)
  686. ++iter;
  687. sStatList.erase(iter);
  688. }
  689. }
  690. void LLStat::reset()
  691. {
  692. U32 i;
  693. mNumValues = 0;
  694. mLastValue = 0.f;
  695. mCurBin = (mNumBins-1);
  696. delete[] mBins;
  697. delete[] mBeginTime;
  698. delete[] mTime;
  699. delete[] mDT;
  700. mBins = new F32[mNumBins];
  701. mBeginTime = new F64[mNumBins];
  702. mTime = new F64[mNumBins];
  703. mDT = new F32[mNumBins];
  704. for (i = 0; i < mNumBins; i++)
  705. {
  706. mBins[i] = 0.f;
  707. mBeginTime[i] = 0.0;
  708. mTime[i] = 0.0;
  709. mDT[i] = 0.f;
  710. }
  711. }
  712. void LLStat::setBeginTime(const F64 time)
  713. {
  714. mBeginTime[mNextBin] = time;
  715. }
  716. void LLStat::addValueTime(const F64 time, const F32 value)
  717. {
  718. if (mNumValues < mNumBins)
  719. {
  720. mNumValues++;
  721. }
  722. // Increment the bin counters.
  723. mCurBin++;
  724. if ((U32)mCurBin == mNumBins)
  725. {
  726. mCurBin = 0;
  727. }
  728. mNextBin++;
  729. if ((U32)mNextBin == mNumBins)
  730. {
  731. mNextBin = 0;
  732. }
  733. mBins[mCurBin] = value;
  734. mTime[mCurBin] = time;
  735. mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]);
  736. //this value is used to prime the min/max calls
  737. mLastTime = mTime[mCurBin];
  738. mLastValue = value;
  739. // Set the begin time for the next stat segment.
  740. mBeginTime[mNextBin] = mTime[mCurBin];
  741. mTime[mNextBin] = mTime[mCurBin];
  742. mDT[mNextBin] = 0.f;
  743. }
  744. void LLStat::start()
  745. {
  746. if (mUseFrameTimer)
  747. {
  748. mBeginTime[mNextBin] = sFrameTimer.getElapsedSeconds();
  749. }
  750. else
  751. {
  752. mBeginTime[mNextBin] = sTimer.getElapsedTimeF64();
  753. }
  754. }
  755. void LLStat::addValue(const F32 value)
  756. {
  757. if (mNumValues < mNumBins)
  758. {
  759. mNumValues++;
  760. }
  761. // Increment the bin counters.
  762. mCurBin++;
  763. if ((U32)mCurBin == mNumBins)
  764. {
  765. mCurBin = 0;
  766. }
  767. mNextBin++;
  768. if ((U32)mNextBin == mNumBins)
  769. {
  770. mNextBin = 0;
  771. }
  772. mBins[mCurBin] = value;
  773. if (mUseFrameTimer)
  774. {
  775. mTime[mCurBin] = sFrameTimer.getElapsedSeconds();
  776. }
  777. else
  778. {
  779. mTime[mCurBin] = sTimer.getElapsedTimeF64();
  780. }
  781. mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]);
  782. //this value is used to prime the min/max calls
  783. mLastTime = mTime[mCurBin];
  784. mLastValue = value;
  785. // Set the begin time for the next stat segment.
  786. mBeginTime[mNextBin] = mTime[mCurBin];
  787. mTime[mNextBin] = mTime[mCurBin];
  788. mDT[mNextBin] = 0.f;
  789. }
  790. F32 LLStat::getMax() const
  791. {
  792. U32 i;
  793. F32 current_max = mLastValue;
  794. if (mNumBins == 0)
  795. {
  796. current_max = 0.f;
  797. }
  798. else
  799. {
  800. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  801. {
  802. // Skip the bin we're currently filling.
  803. if (i == (U32)mNextBin)
  804. {
  805. continue;
  806. }
  807. if (mBins[i] > current_max)
  808. {
  809. current_max = mBins[i];
  810. }
  811. }
  812. }
  813. return current_max;
  814. }
  815. F32 LLStat::getMean() const
  816. {
  817. U32 i;
  818. F32 current_mean = 0.f;
  819. U32 samples = 0;
  820. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  821. {
  822. // Skip the bin we're currently filling.
  823. if (i == (U32)mNextBin)
  824. {
  825. continue;
  826. }
  827. current_mean += mBins[i];
  828. samples++;
  829. }
  830. // There will be a wrap error at 2^32. :)
  831. if (samples != 0)
  832. {
  833. current_mean /= samples;
  834. }
  835. else
  836. {
  837. current_mean = 0.f;
  838. }
  839. return current_mean;
  840. }
  841. F32 LLStat::getMin() const
  842. {
  843. U32 i;
  844. F32 current_min = mLastValue;
  845. if (mNumBins == 0)
  846. {
  847. current_min = 0.f;
  848. }
  849. else
  850. {
  851. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  852. {
  853. // Skip the bin we're currently filling.
  854. if (i == (U32)mNextBin)
  855. {
  856. continue;
  857. }
  858. if (mBins[i] < current_min)
  859. {
  860. current_min = mBins[i];
  861. }
  862. }
  863. }
  864. return current_min;
  865. }
  866. F32 LLStat::getSum() const
  867. {
  868. U32 i;
  869. F32 sum = 0.f;
  870. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  871. {
  872. // Skip the bin we're currently filling.
  873. if (i == (U32)mNextBin)
  874. {
  875. continue;
  876. }
  877. sum += mBins[i];
  878. }
  879. return sum;
  880. }
  881. F32 LLStat::getSumDuration() const
  882. {
  883. U32 i;
  884. F32 sum = 0.f;
  885. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  886. {
  887. // Skip the bin we're currently filling.
  888. if (i == (U32)mNextBin)
  889. {
  890. continue;
  891. }
  892. sum += mDT[i];
  893. }
  894. return sum;
  895. }
  896. F32 LLStat::getPrev(S32 age) const
  897. {
  898. S32 bin;
  899. bin = mCurBin - age;
  900. while (bin < 0)
  901. {
  902. bin += mNumBins;
  903. }
  904. if (bin == mNextBin)
  905. {
  906. // Bogus for bin we're currently working on.
  907. return 0.f;
  908. }
  909. return mBins[bin];
  910. }
  911. F32 LLStat::getPrevPerSec(S32 age) const
  912. {
  913. S32 bin;
  914. bin = mCurBin - age;
  915. while (bin < 0)
  916. {
  917. bin += mNumBins;
  918. }
  919. if (bin == mNextBin)
  920. {
  921. // Bogus for bin we're currently working on.
  922. return 0.f;
  923. }
  924. return mBins[bin] / mDT[bin];
  925. }
  926. F64 LLStat::getPrevBeginTime(S32 age) const
  927. {
  928. S32 bin;
  929. bin = mCurBin - age;
  930. while (bin < 0)
  931. {
  932. bin += mNumBins;
  933. }
  934. if (bin == mNextBin)
  935. {
  936. // Bogus for bin we're currently working on.
  937. return 0.f;
  938. }
  939. return mBeginTime[bin];
  940. }
  941. F64 LLStat::getPrevTime(S32 age) const
  942. {
  943. S32 bin;
  944. bin = mCurBin - age;
  945. while (bin < 0)
  946. {
  947. bin += mNumBins;
  948. }
  949. if (bin == mNextBin)
  950. {
  951. // Bogus for bin we're currently working on.
  952. return 0.f;
  953. }
  954. return mTime[bin];
  955. }
  956. F32 LLStat::getBin(S32 bin) const
  957. {
  958. return mBins[bin];
  959. }
  960. F32 LLStat::getBinPerSec(S32 bin) const
  961. {
  962. return mBins[bin] / mDT[bin];
  963. }
  964. F64 LLStat::getBinBeginTime(S32 bin) const
  965. {
  966. return mBeginTime[bin];
  967. }
  968. F64 LLStat::getBinTime(S32 bin) const
  969. {
  970. return mTime[bin];
  971. }
  972. F32 LLStat::getCurrent() const
  973. {
  974. return mBins[mCurBin];
  975. }
  976. F32 LLStat::getCurrentPerSec() const
  977. {
  978. return mBins[mCurBin] / mDT[mCurBin];
  979. }
  980. F64 LLStat::getCurrentBeginTime() const
  981. {
  982. return mBeginTime[mCurBin];
  983. }
  984. F64 LLStat::getCurrentTime() const
  985. {
  986. return mTime[mCurBin];
  987. }
  988. F32 LLStat::getCurrentDuration() const
  989. {
  990. return mDT[mCurBin];
  991. }
  992. F32 LLStat::getMeanPerSec() const
  993. {
  994. U32 i;
  995. F32 value = 0.f;
  996. F32 dt = 0.f;
  997. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  998. {
  999. // Skip the bin we're currently filling.
  1000. if (i == (U32)mNextBin)
  1001. {
  1002. continue;
  1003. }
  1004. value += mBins[i];
  1005. dt += mDT[i];
  1006. }
  1007. if (dt > 0.f)
  1008. {
  1009. return value/dt;
  1010. }
  1011. else
  1012. {
  1013. return 0.f;
  1014. }
  1015. }
  1016. F32 LLStat::getMeanDuration() const
  1017. {
  1018. F32 dur = 0.0f;
  1019. U32 count = 0;
  1020. for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++)
  1021. {
  1022. if (i == (U32)mNextBin)
  1023. {
  1024. continue;
  1025. }
  1026. dur += mDT[i];
  1027. count++;
  1028. }
  1029. if (count > 0)
  1030. {
  1031. dur /= F32(count);
  1032. return dur;
  1033. }
  1034. else
  1035. {
  1036. return 0.f;
  1037. }
  1038. }
  1039. F32 LLStat::getMaxPerSec() const
  1040. {
  1041. U32 i;
  1042. F32 value;
  1043. if (mNextBin != 0)
  1044. {
  1045. value = mBins[0]/mDT[0];
  1046. }
  1047. else if (mNumValues > 0)
  1048. {
  1049. value = mBins[1]/mDT[1];
  1050. }
  1051. else
  1052. {
  1053. value = 0.f;
  1054. }
  1055. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  1056. {
  1057. // Skip the bin we're currently filling.
  1058. if (i == (U32)mNextBin)
  1059. {
  1060. continue;
  1061. }
  1062. value = llmax(value, mBins[i]/mDT[i]);
  1063. }
  1064. return value;
  1065. }
  1066. F32 LLStat::getMinPerSec() const
  1067. {
  1068. U32 i;
  1069. F32 value;
  1070. if (mNextBin != 0)
  1071. {
  1072. value = mBins[0]/mDT[0];
  1073. }
  1074. else if (mNumValues > 0)
  1075. {
  1076. value = mBins[1]/mDT[1];
  1077. }
  1078. else
  1079. {
  1080. value = 0.f;
  1081. }
  1082. for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
  1083. {
  1084. // Skip the bin we're currently filling.
  1085. if (i == (U32)mNextBin)
  1086. {
  1087. continue;
  1088. }
  1089. value = llmin(value, mBins[i]/mDT[i]);
  1090. }
  1091. return value;
  1092. }
  1093. F32 LLStat::getMinDuration() const
  1094. {
  1095. F32 dur = 0.0f;
  1096. for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++)
  1097. {
  1098. dur = llmin(dur, mDT[i]);
  1099. }
  1100. return dur;
  1101. }
  1102. U32 LLStat::getNumValues() const
  1103. {
  1104. return mNumValues;
  1105. }
  1106. S32 LLStat::getNumBins() const
  1107. {
  1108. return mNumBins;
  1109. }
  1110. S32 LLStat::getCurBin() const
  1111. {
  1112. return mCurBin;
  1113. }
  1114. S32 LLStat::getNextBin() const
  1115. {
  1116. return mNextBin;
  1117. }
  1118. F64 LLStat::getLastTime() const
  1119. {
  1120. return mLastTime;
  1121. }