summaryrefslogtreecommitdiff
path: root/indra/llcommon/llstat.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llstat.cpp')
-rw-r--r--indra/llcommon/llstat.cpp679
1 files changed, 579 insertions, 100 deletions
diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp
index e999934b62..8ba97d7730 100644
--- a/indra/llcommon/llstat.cpp
+++ b/indra/llcommon/llstat.cpp
@@ -1,85 +1,328 @@
/**
* @file llstat.cpp
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llstat.h"
+#include "lllivefile.h"
+#include "llerrorcontrol.h"
#include "llframetimer.h"
#include "timing.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llstl.h"
+#include "u64.h"
+
+
+// statics
+S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
+LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
+std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
+LLStat::stat_map_t LLStat::sStatList;
+
+//------------------------------------------------------------------------
+// Live config file to trigger stats logging
+static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd";
+static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds
-class LLStatAccum::impl
+class LLStatsConfigFile : public LLLiveFile
{
public:
- static const TimeScale IMPL_NUM_SCALES = (TimeScale)(SCALE_TWO_MINUTE + 1);
- static U64 sScaleTimes[IMPL_NUM_SCALES];
+ LLStatsConfigFile()
+ : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE),
+ mChanged(false), mStatsp(NULL) { }
- BOOL mUseFrameTimer;
+ static std::string filename();
+
+protected:
+ /* virtual */ bool loadFile();
- BOOL mRunning;
- U64 mLastTime;
-
- struct Bucket
- {
- F64 accum;
- U64 endTime;
+public:
+ void init(LLPerfStats* statsp);
+ static LLStatsConfigFile& instance();
+ // return the singleton stats config file
- BOOL lastValid;
- F64 lastAccum;
- };
+ bool mChanged;
- Bucket mBuckets[IMPL_NUM_SCALES];
+protected:
+ LLPerfStats* mStatsp;
+};
- BOOL mLastSampleValid;
- F64 mLastSampleValue;
+std::string LLStatsConfigFile::filename()
+{
+ return STATS_CONFIG_FILE_NAME;
+}
+void LLStatsConfigFile::init(LLPerfStats* statsp)
+{
+ mStatsp = statsp;
+}
- impl(bool useFrameTimer);
+LLStatsConfigFile& LLStatsConfigFile::instance()
+{
+ static LLStatsConfigFile the_file;
+ return the_file;
+}
- void reset(U64 when);
- void sum(F64 value);
- void sum(F64 value, U64 when);
+/* virtual */
+// Load and parse the stats configuration file
+bool LLStatsConfigFile::loadFile()
+{
+ if (!mStatsp)
+ {
+ llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
+ return false;
+ }
+ mChanged = true;
+
+ LLSD stats_config;
+ {
+ llifstream file(filename().c_str());
+ if (file.is_open())
+ {
+ LLSDSerialize::fromXML(stats_config, file);
+ if (stats_config.isUndefined())
+ {
+ llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
+ mStatsp->setReportPerformanceDuration( 0.f );
+ return false;
+ }
+ }
+ else
+ { // File went away, turn off stats if it was on
+ if ( mStatsp->frameStatsIsRunning() )
+ {
+ llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
+ mStatsp->setReportPerformanceDuration( 0.f );
+ }
+ return true;
+ }
+ }
+
+ F32 duration = 0.f;
+ F32 interval = 0.f;
+ S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
+
+ const char * w = "duration";
+ if (stats_config.has(w))
+ {
+ duration = (F32)stats_config[w].asReal();
+ }
+ w = "interval";
+ if (stats_config.has(w))
+ {
+ interval = (F32)stats_config[w].asReal();
+ }
+ w = "flags";
+ if (stats_config.has(w))
+ {
+ flags = (S32)stats_config[w].asInteger();
+ if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
+ duration > 0)
+ { // No flags passed in, but have a duration, so reset to basic stats
+ flags = LLPerfBlock::LLSTATS_BASIC_STATS;
+ }
+ }
+
+ mStatsp->setReportPerformanceDuration( duration, flags );
+ mStatsp->setReportPerformanceInterval( interval );
+
+ if ( duration > 0 )
+ {
+ if ( interval == 0.f )
+ {
+ llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl;
+ }
+ else
+ {
+ llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl;
+ }
+ }
+ else
+ {
+ llinfos << "Performance stats recording turned off" << llendl;
+ }
+ return true;
+}
- F32 meanValue(TimeScale scale) const;
- U64 getCurrentUsecs() const;
- // Get current microseconds based on timer type
-};
+//------------------------------------------------------------------------
+LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) :
+ mFrameStatsFileFailure(FALSE),
+ mSkipFirstFrameStats(FALSE),
+ mProcessName(process_name),
+ mProcessPID(process_pid),
+ mReportPerformanceStatInterval(1.f),
+ mReportPerformanceStatEnd(0.0)
+{ }
-U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
+LLPerfStats::~LLPerfStats()
{
+ LLPerfBlock::clearDynamicStats();
+ mFrameStatsFile.close();
+}
+
+void LLPerfStats::init()
+{
+ // Initialize the stats config file instance.
+ (void) LLStatsConfigFile::instance().init(this);
+ (void) LLStatsConfigFile::instance().checkAndReload();
+}
+
+// Open file for statistics
+void LLPerfStats::openPerfStatsFile()
+{
+ if ( !mFrameStatsFile
+ && !mFrameStatsFileFailure )
+ {
+ std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID);
+ mFrameStatsFile.close();
+ mFrameStatsFile.clear();
+ mFrameStatsFile.open(stats_file, llofstream::out);
+ if ( mFrameStatsFile.fail() )
+ {
+ llinfos << "Error opening statistics log file " << stats_file << llendl;
+ mFrameStatsFileFailure = TRUE;
+ }
+ else
+ {
+ LLSD process_info = LLSD::emptyMap();
+ process_info["name"] = mProcessName;
+ process_info["pid"] = (LLSD::Integer) mProcessPID;
+ process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval;
+ // Add process-specific info.
+ addProcessHeaderInfo(process_info);
+
+ mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl;
+ }
+ }
+}
+
+// Dump out performance metrics over some time interval
+void LLPerfStats::dumpIntervalPerformanceStats()
+{
+ // Ensure output file is OK
+ openPerfStatsFile();
+
+ if ( mFrameStatsFile )
+ {
+ LLSD stats = LLSD::emptyMap();
+
+ LLStatAccum::TimeScale scale;
+ if ( getReportPerformanceInterval() == 0.f )
+ {
+ scale = LLStatAccum::SCALE_PER_FRAME;
+ }
+ else if ( getReportPerformanceInterval() < 0.5f )
+ {
+ scale = LLStatAccum::SCALE_100MS;
+ }
+ else
+ {
+ scale = LLStatAccum::SCALE_SECOND;
+ }
+
+ // Write LLSD into log
+ stats["utc_time"] = (LLSD::String) LLError::utcTime();
+ stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch
+ stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount();
+
+ // Add process-specific frame info.
+ addProcessFrameInfo(stats, scale);
+ LLPerfBlock::addStatsToLLSDandReset( stats, scale );
+
+ mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl;
+ }
+}
+
+// Set length of performance stat recording.
+// If turning stats on, caller must provide flags
+void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
+{
+ if ( seconds <= 0.f )
+ {
+ mReportPerformanceStatEnd = 0.0;
+ LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
+ mFrameStatsFile.close();
+ LLPerfBlock::clearDynamicStats();
+ }
+ else
+ {
+ mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
+ // Clear failure flag to try and create the log file once
+ mFrameStatsFileFailure = FALSE;
+ mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
+ LLPerfBlock::setStatsFlags(flags);
+ }
+}
+
+void LLPerfStats::updatePerFrameStats()
+{
+ (void) LLStatsConfigFile::instance().checkAndReload();
+ static LLFrameTimer performance_stats_timer;
+ if ( frameStatsIsRunning() )
+ {
+ if ( mReportPerformanceStatInterval == 0 )
+ { // Record info every frame
+ if ( mSkipFirstFrameStats )
+ { // Skip the first time - was started this frame
+ mSkipFirstFrameStats = FALSE;
+ }
+ else
+ {
+ dumpIntervalPerformanceStats();
+ }
+ }
+ else
+ {
+ performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() );
+ if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval ))
+ {
+ dumpIntervalPerformanceStats();
+ }
+ }
+
+ if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd )
+ { // Reached end of time, clear it to stop reporting
+ setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly
+ llinfos << "Recording performance stats completed" << llendl;
+ }
+ }
+}
+
+
+//------------------------------------------------------------------------
+
+U64 LLStatAccum::sScaleTimes[NUM_SCALES] =
+{
+ USEC_PER_SEC / 10, // 100 millisec
USEC_PER_SEC * 1, // seconds
USEC_PER_SEC * 60, // minutes
- USEC_PER_SEC * 60 * 2 // minutes
-#if 0
+#if ENABLE_LONG_TIME_STATS
// enable these when more time scales are desired
USEC_PER_SEC * 60*60, // hours
USEC_PER_SEC * 24*60*60, // days
@@ -88,32 +331,41 @@ U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
};
-LLStatAccum::impl::impl(bool useFrameTimer)
+
+LLStatAccum::LLStatAccum(bool useFrameTimer)
+ : mUseFrameTimer(useFrameTimer),
+ mRunning(FALSE),
+ mLastTime(0),
+ mLastSampleValue(0.0),
+ mLastSampleValid(FALSE)
+{
+}
+
+LLStatAccum::~LLStatAccum()
{
- mUseFrameTimer = useFrameTimer;
- mRunning = FALSE;
- mLastSampleValid = FALSE;
}
-void LLStatAccum::impl::reset(U64 when)
+
+
+void LLStatAccum::reset(U64 when)
{
mRunning = TRUE;
mLastTime = when;
- for (int i = 0; i < IMPL_NUM_SCALES; ++i)
+ for (int i = 0; i < NUM_SCALES; ++i)
{
mBuckets[i].accum = 0.0;
mBuckets[i].endTime = when + sScaleTimes[i];
- mBuckets[i].lastValid = FALSE;
+ mBuckets[i].lastValid = false;
}
}
-void LLStatAccum::impl::sum(F64 value)
+void LLStatAccum::sum(F64 value)
{
sum(value, getCurrentUsecs());
}
-void LLStatAccum::impl::sum(F64 value, U64 when)
+void LLStatAccum::sum(F64 value, U64 when)
{
if (!mRunning)
{
@@ -130,7 +382,10 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
return;
}
- for (int i = 0; i < IMPL_NUM_SCALES; ++i)
+ // how long is this value for
+ U64 timeSpan = when - mLastTime;
+
+ for (int i = 0; i < NUM_SCALES; ++i)
{
Bucket& bucket = mBuckets[i];
@@ -142,8 +397,6 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
{
U64 timeScale = sScaleTimes[i];
- U64 timeSpan = when - mLastTime;
- // how long is this value for
U64 timeLeft = when - bucket.endTime;
// how much time is left after filling this bucket
@@ -151,7 +404,7 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
{
F64 valueLeft = value * timeLeft / timeSpan;
- bucket.lastValid = TRUE;
+ bucket.lastValid = true;
bucket.lastAccum = bucket.accum + (value - valueLeft);
bucket.accum = valueLeft;
bucket.endTime += timeScale;
@@ -160,7 +413,7 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
{
U64 timeTail = timeLeft % timeScale;
- bucket.lastValid = TRUE;
+ bucket.lastValid = true;
bucket.lastAccum = value * timeScale / timeSpan;
bucket.accum = value * timeTail / timeSpan;
bucket.endTime += (timeLeft - timeTail) + timeScale;
@@ -172,13 +425,18 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
}
-F32 LLStatAccum::impl::meanValue(TimeScale scale) const
+F32 LLStatAccum::meanValue(TimeScale scale) const
{
if (!mRunning)
{
return 0.0;
}
- if (scale < 0 || scale >= IMPL_NUM_SCALES)
+ if ( scale == SCALE_PER_FRAME )
+ { // Per-frame not supported here
+ scale = SCALE_100MS;
+ }
+
+ if (scale < 0 || scale >= NUM_SCALES)
{
llwarns << "llStatAccum::meanValue called for unsupported scale: "
<< scale << llendl;
@@ -208,7 +466,7 @@ F32 LLStatAccum::impl::meanValue(TimeScale scale) const
}
-U64 LLStatAccum::impl::getCurrentUsecs() const
+U64 LLStatAccum::getCurrentUsecs() const
{
if (mUseFrameTimer)
{
@@ -221,24 +479,43 @@ U64 LLStatAccum::impl::getCurrentUsecs() const
}
+// ------------------------------------------------------------------------
-
-
-LLStatAccum::LLStatAccum(bool useFrameTimer)
- : m(* new impl(useFrameTimer))
+LLStatRate::LLStatRate(bool use_frame_timer)
+ : LLStatAccum(use_frame_timer)
{
}
-LLStatAccum::~LLStatAccum()
+void LLStatRate::count(U32 value)
{
- delete &m;
+ sum((F64)value * sScaleTimes[SCALE_SECOND]);
}
-F32 LLStatAccum::meanValue(TimeScale scale) const
-{
- return m.meanValue(scale);
-}
+void LLStatRate::mark()
+ {
+ // Effectively the same as count(1), but sets mLastSampleValue
+ U64 when = getCurrentUsecs();
+
+ if ( mRunning
+ && (when > mLastTime) )
+ { // Set mLastSampleValue to the time from the last mark()
+ F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND];
+ if ( duration > 0.0 )
+ {
+ mLastSampleValue = 1.0 / duration;
+ }
+ else
+ {
+ mLastSampleValue = 0.0;
+ }
+ }
+
+ sum( (F64) sScaleTimes[SCALE_SECOND], when);
+ }
+
+
+// ------------------------------------------------------------------------
LLStatMeasure::LLStatMeasure(bool use_frame_timer)
@@ -248,79 +525,272 @@ LLStatMeasure::LLStatMeasure(bool use_frame_timer)
void LLStatMeasure::sample(F64 value)
{
- U64 when = m.getCurrentUsecs();
+ U64 when = getCurrentUsecs();
- if (m.mLastSampleValid)
+ if (mLastSampleValid)
{
- F64 avgValue = (value + m.mLastSampleValue) / 2.0;
- F64 interval = (F64)(when - m.mLastTime);
+ F64 avgValue = (value + mLastSampleValue) / 2.0;
+ F64 interval = (F64)(when - mLastTime);
- m.sum(avgValue * interval, when);
+ sum(avgValue * interval, when);
}
else
{
- m.reset(when);
+ reset(when);
}
- m.mLastSampleValid = TRUE;
- m.mLastSampleValue = value;
+ mLastSampleValid = TRUE;
+ mLastSampleValue = value;
}
-LLStatRate::LLStatRate(bool use_frame_timer)
- : LLStatAccum(use_frame_timer)
+// ------------------------------------------------------------------------
+
+LLStatTime::LLStatTime(const std::string & key)
+ : LLStatAccum(false),
+ mFrameNumber(LLFrameTimer::getFrameCount()),
+ mTotalTimeInFrame(0),
+ mKey(key)
+#if LL_DEBUG
+ , mRunning(FALSE)
+#endif
{
}
-void LLStatRate::count(U32 value)
+void LLStatTime::start()
{
- m.sum((F64)value * impl::sScaleTimes[SCALE_SECOND]);
+ // Reset frame accumluation if the frame number has changed
+ U32 frame_number = LLFrameTimer::getFrameCount();
+ if ( frame_number != mFrameNumber )
+ {
+ mFrameNumber = frame_number;
+ mTotalTimeInFrame = 0;
+ }
+
+ sum(0.0);
+
+#if LL_DEBUG
+ // Shouldn't be running already
+ llassert( !mRunning );
+ mRunning = TRUE;
+#endif
}
+void LLStatTime::stop()
+{
+ U64 end_time = getCurrentUsecs();
+ U64 duration = end_time - mLastTime;
+ sum(F64(duration), end_time);
+ //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl;
+ mTotalTimeInFrame += duration;
-LLStatTime::LLStatTime(bool use_frame_timer)
- : LLStatAccum(use_frame_timer)
+#if LL_DEBUG
+ mRunning = FALSE;
+#endif
+}
+
+/* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const
{
+ if ( LLStatAccum::SCALE_PER_FRAME == scale )
+ {
+ return mTotalTimeInFrame;
+ }
+ else
+ {
+ return LLStatAccum::meanValue(scale);
+ }
}
-void LLStatTime::start()
+
+// ------------------------------------------------------------------------
+
+
+// Use this constructor for pre-defined LLStatTime objects
+LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL)
{
- m.sum(0.0);
+ if (mPredefinedStat)
+ {
+ // If dynamic stats are turned on, this will create a separate entry in the stat map.
+ initDynamicStat(mPredefinedStat->mKey);
+
+ // Start predefined stats. These stats are not part of the stat map.
+ mPredefinedStat->start();
+ }
}
-void LLStatTime::stop()
+// Use this constructor for normal, optional LLPerfBlock time slices
+LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
- U64 endTime = m.getCurrentUsecs();
- m.sum((F64)(endTime - m.mLastTime), endTime);
+ if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
+ { // These are off unless the base set is enabled
+ return;
+ }
+
+ initDynamicStat(key);
}
+
+// Use this constructor for dynamically created LLPerfBlock time slices
+// that are only enabled by specific control flags
+LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
+{
+ if ((sStatsFlags & flags) == 0)
+ {
+ return;
+ }
+
+ if (NULL == key2 || strlen(key2) == 0)
+ {
+ initDynamicStat(key1);
+ }
+ else
+ {
+ std::ostringstream key;
+ key << key1 << "_" << key2;
+ initDynamicStat(key.str());
+ }
+}
+
+// Set up the result data map if dynamic stats are enabled
+void LLPerfBlock::initDynamicStat(const std::string& key)
+{
+ // Early exit if dynamic stats aren't enabled.
+ if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
+ return;
+
+ mLastPath = sCurrentStatPath; // Save and restore current path
+ sCurrentStatPath += "/" + key; // Add key to current path
+
+ // See if the LLStatTime object already exists
+ stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath);
+ if ( iter == sStatMap.end() )
+ {
+ // StatEntry object doesn't exist, so create it
+ mDynamicStat = new StatEntry( key );
+ sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path
+ }
+ else
+ {
+ // Found this path in the map, use the object there
+ mDynamicStat = (*iter).second; // Get StatEntry for the current path
+ }
+
+ if (mDynamicStat)
+ {
+ mDynamicStat->mStat.start();
+ mDynamicStat->mCount++;
+ }
+ else
+ {
+ llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl;
+ sCurrentStatPath = mLastPath;
+ }
+}
+
+
+// Destructor does the time accounting
+LLPerfBlock::~LLPerfBlock()
+{
+ if (mPredefinedStat) mPredefinedStat->stop();
+ if (mDynamicStat)
+ {
+ mDynamicStat->mStat.stop();
+ sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block
+ }
+}
+
+
+// Clear the map of any dynamic stats. Static routine
+void LLPerfBlock::clearDynamicStats()
+{
+ std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer());
+ sStatMap.clear();
+}
+
+// static - Extract the stat info into LLSD
+void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
+ LLStatAccum::TimeScale scale )
+{
+ // If we aren't in per-frame scale, we need to go from second to microsecond.
+ U32 scale_adjustment = 1;
+ if (LLStatAccum::SCALE_PER_FRAME != scale)
+ {
+ scale_adjustment = USEC_PER_SEC;
+ }
+ stat_map_t::iterator iter = sStatMap.begin();
+ for ( ; iter != sStatMap.end(); ++iter )
+ { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time
+ const std::string & stats_full_path = (*iter).first;
+
+ StatEntry * stat = (*iter).second;
+ if (stat)
+ {
+ if (stat->mCount > 0)
+ {
+ stats[stats_full_path] = LLSD::emptyMap();
+ stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale));
+ if (stat->mCount > 1)
+ {
+ stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount;
+ }
+ stat->mCount = 0;
+ }
+ }
+ else
+ { // WTF? Shouldn't have a NULL pointer in the map.
+ llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
+ }
+ }
+}
+// ------------------------------------------------------------------------
+
LLTimer LLStat::sTimer;
LLFrameTimer LLStat::sFrameTimer;
-LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
+void LLStat::init()
{
- llassert(num_bins > 0);
- U32 i;
- mUseFrameTimer = use_frame_timer;
+ llassert(mNumBins > 0);
mNumValues = 0;
mLastValue = 0.f;
mLastTime = 0.f;
- mNumBins = num_bins;
mCurBin = (mNumBins-1);
mNextBin = 0;
mBins = new F32[mNumBins];
mBeginTime = new F64[mNumBins];
mTime = new F64[mNumBins];
mDT = new F32[mNumBins];
- for (i = 0; i < mNumBins; i++)
+ for (U32 i = 0; i < mNumBins; i++)
{
mBins[i] = 0.f;
mBeginTime[i] = 0.0;
mTime[i] = 0.0;
mDT[i] = 0.f;
}
+
+ if (!mName.empty())
+ {
+ stat_map_t::iterator iter = sStatList.find(mName);
+ if (iter != sStatList.end())
+ llwarns << "LLStat with duplicate name: " << mName << llendl;
+ sStatList.insert(std::make_pair(mName, this));
+ }
+}
+
+LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
+ : mUseFrameTimer(use_frame_timer),
+ mNumBins(num_bins)
+{
+ init();
+}
+
+LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
+ : mUseFrameTimer(use_frame_timer),
+ mNumBins(num_bins),
+ mName(name)
+{
+ init();
}
LLStat::~LLStat()
@@ -329,6 +799,15 @@ LLStat::~LLStat()
delete[] mBeginTime;
delete[] mTime;
delete[] mDT;
+
+ if (!mName.empty())
+ {
+ // handle multiple entries with the same name
+ stat_map_t::iterator iter = sStatList.find(mName);
+ while (iter != sStatList.end() && iter->second != this)
+ ++iter;
+ sStatList.erase(iter);
+ }
}
void LLStat::reset()