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

游戏引擎

开发平台:

C++ Builder

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