aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon
diff options
context:
space:
mode:
authorMcCabe Maxsted2009-01-14 07:56:23 -0700
committerMcCabe Maxsted2009-01-14 07:56:23 -0700
commitc25939480d6134c200a14ecab23eee60b175596f (patch)
tree0ed050b7005f87062e11fe1044c3a1c838ecc412 /linden/indra/llcommon
parentAdded the 'Return to World' inventory option (diff)
downloadmeta-impy-c25939480d6134c200a14ecab23eee60b175596f.zip
meta-impy-c25939480d6134c200a14ecab23eee60b175596f.tar.gz
meta-impy-c25939480d6134c200a14ecab23eee60b175596f.tar.bz2
meta-impy-c25939480d6134c200a14ecab23eee60b175596f.tar.xz
Updated llmessage
Diffstat (limited to 'linden/indra/llcommon')
-rw-r--r--linden/indra/llcommon/llstat.cpp562
-rw-r--r--linden/indra/llcommon/llstat.h142
2 files changed, 618 insertions, 86 deletions
diff --git a/linden/indra/llcommon/llstat.cpp b/linden/indra/llcommon/llstat.cpp
index 4b79fcb..706acdb 100644
--- a/linden/indra/llcommon/llstat.cpp
+++ b/linden/indra/llcommon/llstat.cpp
@@ -31,55 +31,288 @@
31#include "linden_common.h" 31#include "linden_common.h"
32 32
33#include "llstat.h" 33#include "llstat.h"
34#include "lllivefile.h"
35#include "llerrorcontrol.h"
34#include "llframetimer.h" 36#include "llframetimer.h"
35#include "timing.h" 37#include "timing.h"
38#include "llsd.h"
39#include "llsdserialize.h"
40#include "llstl.h"
41#include "u64.h"
36 42
37class LLStatAccum::impl 43
44// statics
45BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
46LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
47std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
48
49//------------------------------------------------------------------------
50// Live config file to trigger stats logging
51static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd";
52static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds
53
54class LLStatsConfigFile : public LLLiveFile
38{ 55{
39public: 56public:
40 static const TimeScale IMPL_NUM_SCALES = (TimeScale)(SCALE_TWO_MINUTE + 1); 57 LLStatsConfigFile()
41 static U64 sScaleTimes[IMPL_NUM_SCALES]; 58 : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE),
59 mChanged(false), mStatsp(NULL) { }
42 60
43 BOOL mUseFrameTimer; 61 static std::string filename();
62
63protected:
64 /* virtual */ void loadFile();
44 65
45 BOOL mRunning; 66public:
46 U64 mLastTime; 67 void init(LLPerfStats* statsp);
47 68 static LLStatsConfigFile& instance();
48 struct Bucket 69 // return the singleton stats config file
49 {
50 F64 accum;
51 U64 endTime;
52 70
53 BOOL lastValid; 71 bool mChanged;
54 F64 lastAccum;
55 };
56 72
57 Bucket mBuckets[IMPL_NUM_SCALES]; 73protected:
74 LLPerfStats* mStatsp;
75};
58 76
59 BOOL mLastSampleValid; 77std::string LLStatsConfigFile::filename()
60 F64 mLastSampleValue; 78{
79 return STATS_CONFIG_FILE_NAME;
80}
61 81
82void LLStatsConfigFile::init(LLPerfStats* statsp)
83{
84 mStatsp = statsp;
85}
62 86
63 impl(bool useFrameTimer); 87LLStatsConfigFile& LLStatsConfigFile::instance()
88{
89 static LLStatsConfigFile the_file;
90 return the_file;
91}
64 92
65 void reset(U64 when);
66 93
67 void sum(F64 value); 94/* virtual */
68 void sum(F64 value, U64 when); 95// Load and parse the stats configuration file
96void LLStatsConfigFile::loadFile()
97{
98 if (!mStatsp)
99 {
100 llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
101 return;
102 }
103 mChanged = true;
104
105 LLSD stats_config;
106 {
107 llifstream file(filename().c_str());
108 if (file.is_open())
109 {
110 LLSDSerialize::fromXML(stats_config, file);
111 if (stats_config.isUndefined())
112 {
113 llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
114 mStatsp->setReportPerformanceDuration( 0.f );
115 return;
116 }
117 }
118 else
119 { // File went away, turn off stats if it was on
120 if ( mStatsp->frameStatsIsRunning() )
121 {
122 llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
123 mStatsp->setReportPerformanceDuration( 0.f );
124 }
125 return;
126 }
127 }
128
129 F32 duration = 0.f;
130 F32 interval = 0.f;
131
132 const char * w = "duration";
133 if (stats_config.has(w))
134 {
135 duration = (F32)stats_config[w].asReal();
136 }
137 w = "interval";
138 if (stats_config.has(w))
139 {
140 interval = (F32)stats_config[w].asReal();
141 }
142
143 mStatsp->setReportPerformanceDuration( duration );
144 mStatsp->setReportPerformanceInterval( interval );
145
146 if ( duration > 0 )
147 {
148 if ( interval == 0.f )
149 {
150 llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl;
151 }
152 else
153 {
154 llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl;
155 }
156 }
157 else
158 {
159 llinfos << "Performance stats recording turned off" << llendl;
160 }
161}
69 162
70 F32 meanValue(TimeScale scale) const;
71 163
72 U64 getCurrentUsecs() const; 164//------------------------------------------------------------------------
73 // Get current microseconds based on timer type
74};
75 165
166LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) :
167 mFrameStatsFileFailure(FALSE),
168 mSkipFirstFrameStats(FALSE),
169 mProcessName(process_name),
170 mProcessPID(process_pid),
171 mReportPerformanceStatInterval(1.f),
172 mReportPerformanceStatEnd(0.0)
173{ }
76 174
77U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] = 175LLPerfStats::~LLPerfStats()
176{
177 LLPerfBlock::clearDynamicStats();
178 mFrameStatsFile.close();
179}
180
181void LLPerfStats::init()
182{
183 // Initialize the stats config file instance.
184 (void) LLStatsConfigFile::instance().init(this);
185 (void) LLStatsConfigFile::instance().checkAndReload();
186}
187
188// Open file for statistics
189void LLPerfStats::openPerfStatsFile()
190{
191 if ( !mFrameStatsFile
192 && !mFrameStatsFileFailure )
193 {
194 std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID);
195 mFrameStatsFile.close();
196 mFrameStatsFile.clear();
197 mFrameStatsFile.open(stats_file, llofstream::out);
198 if ( mFrameStatsFile.fail() )
199 {
200 llinfos << "Error opening statistics log file " << stats_file << llendl;
201 mFrameStatsFileFailure = TRUE;
202 }
203 else
204 {
205 LLSD process_info = LLSD::emptyMap();
206 process_info["name"] = mProcessName;
207 process_info["pid"] = (LLSD::Integer) mProcessPID;
208 process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval;
209 // Add process-specific info.
210 addProcessHeaderInfo(process_info);
211
212 mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl;
213 }
214 }
215}
216
217// Dump out performance metrics over some time interval
218void LLPerfStats::dumpIntervalPerformanceStats()
219{
220 // Ensure output file is OK
221 openPerfStatsFile();
222
223 if ( mFrameStatsFile )
224 {
225 LLSD stats = LLSD::emptyMap();
226
227 LLStatAccum::TimeScale scale;
228 if ( getReportPerformanceInterval() == 0.f )
229 {
230 scale = LLStatAccum::SCALE_PER_FRAME;
231 }
232 else if ( getReportPerformanceInterval() < 0.5f )
233 {
234 scale = LLStatAccum::SCALE_100MS;
235 }
236 else
237 {
238 scale = LLStatAccum::SCALE_SECOND;
239 }
240
241 // Write LLSD into log
242 stats["utc_time"] = (LLSD::String) LLError::utcTime();
243 stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch
244 stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount();
245
246 // Add process-specific frame info.
247 addProcessFrameInfo(stats, scale);
248 LLPerfBlock::addStatsToLLSDandReset( stats, scale );
249
250 mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl;
251 }
252}
253
254// Set length of performance stat recording
255void LLPerfStats::setReportPerformanceDuration( F32 seconds )
256{
257 if ( seconds <= 0.f )
258 {
259 mReportPerformanceStatEnd = 0.0;
260 LLPerfBlock::setStatsEnabled( FALSE );
261 mFrameStatsFile.close();
262 LLPerfBlock::clearDynamicStats();
263 }
264 else
265 {
266 mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
267 // Clear failure flag to try and create the log file once
268 mFrameStatsFileFailure = FALSE;
269 LLPerfBlock::setStatsEnabled( TRUE );
270 mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
271 }
272}
273
274void LLPerfStats::updatePerFrameStats()
275{
276 (void) LLStatsConfigFile::instance().checkAndReload();
277 static LLFrameTimer performance_stats_timer;
278 if ( frameStatsIsRunning() )
279 {
280 if ( mReportPerformanceStatInterval == 0 )
281 { // Record info every frame
282 if ( mSkipFirstFrameStats )
283 { // Skip the first time - was started this frame
284 mSkipFirstFrameStats = FALSE;
285 }
286 else
287 {
288 dumpIntervalPerformanceStats();
289 }
290 }
291 else
292 {
293 performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() );
294 if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval ))
295 {
296 dumpIntervalPerformanceStats();
297 }
298 }
299
300 if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd )
301 { // Reached end of time, clear it to stop reporting
302 setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly
303 llinfos << "Recording performance stats completed" << llendl;
304 }
305 }
306}
307
308
309//------------------------------------------------------------------------
310
311U64 LLStatAccum::sScaleTimes[NUM_SCALES] =
78{ 312{
79 USEC_PER_SEC / 10, // 100 millisec 313 USEC_PER_SEC / 10, // 100 millisec
80 USEC_PER_SEC * 1, // seconds 314 USEC_PER_SEC * 1, // seconds
81 USEC_PER_SEC * 60, // minutes 315 USEC_PER_SEC * 60, // minutes
82 USEC_PER_SEC * 60 * 2 // two minutes
83#if ENABLE_LONG_TIME_STATS 316#if ENABLE_LONG_TIME_STATS
84 // enable these when more time scales are desired 317 // enable these when more time scales are desired
85 USEC_PER_SEC * 60*60, // hours 318 USEC_PER_SEC * 60*60, // hours
@@ -89,19 +322,27 @@ U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
89}; 322};
90 323
91 324
92LLStatAccum::impl::impl(bool useFrameTimer) 325
326LLStatAccum::LLStatAccum(bool useFrameTimer)
327 : mUseFrameTimer(useFrameTimer),
328 mRunning(FALSE),
329 mLastSampleValue(0.0),
330 mLastSampleValid(FALSE)
331{
332}
333
334LLStatAccum::~LLStatAccum()
93{ 335{
94 mUseFrameTimer = useFrameTimer;
95 mRunning = FALSE;
96 mLastSampleValid = FALSE;
97} 336}
98 337
99void LLStatAccum::impl::reset(U64 when) 338
339
340void LLStatAccum::reset(U64 when)
100{ 341{
101 mRunning = TRUE; 342 mRunning = TRUE;
102 mLastTime = when; 343 mLastTime = when;
103 344
104 for (int i = 0; i < IMPL_NUM_SCALES; ++i) 345 for (int i = 0; i < NUM_SCALES; ++i)
105 { 346 {
106 mBuckets[i].accum = 0.0; 347 mBuckets[i].accum = 0.0;
107 mBuckets[i].endTime = when + sScaleTimes[i]; 348 mBuckets[i].endTime = when + sScaleTimes[i];
@@ -109,12 +350,12 @@ void LLStatAccum::impl::reset(U64 when)
109 } 350 }
110} 351}
111 352
112void LLStatAccum::impl::sum(F64 value) 353void LLStatAccum::sum(F64 value)
113{ 354{
114 sum(value, getCurrentUsecs()); 355 sum(value, getCurrentUsecs());
115} 356}
116 357
117void LLStatAccum::impl::sum(F64 value, U64 when) 358void LLStatAccum::sum(F64 value, U64 when)
118{ 359{
119 if (!mRunning) 360 if (!mRunning)
120 { 361 {
@@ -131,7 +372,10 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
131 return; 372 return;
132 } 373 }
133 374
134 for (int i = 0; i < IMPL_NUM_SCALES; ++i) 375 // how long is this value for
376 U64 timeSpan = when - mLastTime;
377
378 for (int i = 0; i < NUM_SCALES; ++i)
135 { 379 {
136 Bucket& bucket = mBuckets[i]; 380 Bucket& bucket = mBuckets[i];
137 381
@@ -143,8 +387,6 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
143 { 387 {
144 U64 timeScale = sScaleTimes[i]; 388 U64 timeScale = sScaleTimes[i];
145 389
146 U64 timeSpan = when - mLastTime;
147 // how long is this value for
148 U64 timeLeft = when - bucket.endTime; 390 U64 timeLeft = when - bucket.endTime;
149 // how much time is left after filling this bucket 391 // how much time is left after filling this bucket
150 392
@@ -173,13 +415,18 @@ void LLStatAccum::impl::sum(F64 value, U64 when)
173} 415}
174 416
175 417
176F32 LLStatAccum::impl::meanValue(TimeScale scale) const 418F32 LLStatAccum::meanValue(TimeScale scale) const
177{ 419{
178 if (!mRunning) 420 if (!mRunning)
179 { 421 {
180 return 0.0; 422 return 0.0;
181 } 423 }
182 if (scale < 0 || scale >= IMPL_NUM_SCALES) 424 if ( scale == SCALE_PER_FRAME )
425 { // Per-frame not supported here
426 scale = SCALE_100MS;
427 }
428
429 if (scale < 0 || scale >= NUM_SCALES)
183 { 430 {
184 llwarns << "llStatAccum::meanValue called for unsupported scale: " 431 llwarns << "llStatAccum::meanValue called for unsupported scale: "
185 << scale << llendl; 432 << scale << llendl;
@@ -209,7 +456,7 @@ F32 LLStatAccum::impl::meanValue(TimeScale scale) const
209} 456}
210 457
211 458
212U64 LLStatAccum::impl::getCurrentUsecs() const 459U64 LLStatAccum::getCurrentUsecs() const
213{ 460{
214 if (mUseFrameTimer) 461 if (mUseFrameTimer)
215 { 462 {
@@ -222,25 +469,44 @@ U64 LLStatAccum::impl::getCurrentUsecs() const
222} 469}
223 470
224 471
472// ------------------------------------------------------------------------
225 473
226 474LLStatRate::LLStatRate(bool use_frame_timer)
227 475 : LLStatAccum(use_frame_timer)
228LLStatAccum::LLStatAccum(bool useFrameTimer)
229 : m(* new impl(useFrameTimer))
230{ 476{
231} 477}
232 478
233LLStatAccum::~LLStatAccum() 479void LLStatRate::count(U32 value)
234{ 480{
235 delete &m; 481 sum((F64)value * sScaleTimes[SCALE_SECOND]);
236} 482}
237 483
238F32 LLStatAccum::meanValue(TimeScale scale) const 484
239{ 485void LLStatRate::mark()
240 return m.meanValue(scale); 486 {
241} 487 // Effectively the same as count(1), but sets mLastSampleValue
488 U64 when = getCurrentUsecs();
489
490 if ( mRunning
491 && (when > mLastTime) )
492 { // Set mLastSampleValue to the time from the last mark()
493 F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND];
494 if ( duration > 0.0 )
495 {
496 mLastSampleValue = 1.0 / duration;
497 }
498 else
499 {
500 mLastSampleValue = 0.0;
501 }
502 }
503
504 sum( (F64) sScaleTimes[SCALE_SECOND], when);
505 }
242 506
243 507
508// ------------------------------------------------------------------------
509
244 510
245LLStatMeasure::LLStatMeasure(bool use_frame_timer) 511LLStatMeasure::LLStatMeasure(bool use_frame_timer)
246 : LLStatAccum(use_frame_timer) 512 : LLStatAccum(use_frame_timer)
@@ -249,53 +515,209 @@ LLStatMeasure::LLStatMeasure(bool use_frame_timer)
249 515
250void LLStatMeasure::sample(F64 value) 516void LLStatMeasure::sample(F64 value)
251{ 517{
252 U64 when = m.getCurrentUsecs(); 518 U64 when = getCurrentUsecs();
253 519
254 if (m.mLastSampleValid) 520 if (mLastSampleValid)
255 { 521 {
256 F64 avgValue = (value + m.mLastSampleValue) / 2.0; 522 F64 avgValue = (value + mLastSampleValue) / 2.0;
257 F64 interval = (F64)(when - m.mLastTime); 523 F64 interval = (F64)(when - mLastTime);
258 524
259 m.sum(avgValue * interval, when); 525 sum(avgValue * interval, when);
260 } 526 }
261 else 527 else
262 { 528 {
263 m.reset(when); 529 reset(when);
264 } 530 }
265 531
266 m.mLastSampleValid = TRUE; 532 mLastSampleValid = TRUE;
267 m.mLastSampleValue = value; 533 mLastSampleValue = value;
268} 534}
269 535
270 536
271LLStatRate::LLStatRate(bool use_frame_timer) 537// ------------------------------------------------------------------------
272 : LLStatAccum(use_frame_timer) 538
539LLStatTime::LLStatTime(const std::string & key)
540 : LLStatAccum(false),
541 mFrameNumber(LLFrameTimer::getFrameCount()),
542 mTotalTimeInFrame(0),
543 mKey(key)
544#if LL_DEBUG
545 , mRunning(FALSE)
546#endif
273{ 547{
274} 548}
275 549
276void LLStatRate::count(U32 value) 550void LLStatTime::start()
551{
552 // Reset frame accumluation if the frame number has changed
553 U32 frame_number = LLFrameTimer::getFrameCount();
554 if ( frame_number != mFrameNumber )
555 {
556 mFrameNumber = frame_number;
557 mTotalTimeInFrame = 0;
558 }
559
560 sum(0.0);
561
562#if LL_DEBUG
563 // Shouldn't be running already
564 llassert( !mRunning );
565 mRunning = TRUE;
566#endif
567}
568
569void LLStatTime::stop()
570{
571 U64 end_time = getCurrentUsecs();
572 U64 duration = end_time - mLastTime;
573 sum(F64(duration), end_time);
574 //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl;
575 mTotalTimeInFrame += duration;
576
577#if LL_DEBUG
578 mRunning = FALSE;
579#endif
580}
581
582/* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const
277{ 583{
278 m.sum((F64)value * impl::sScaleTimes[SCALE_SECOND]); 584 if ( LLStatAccum::SCALE_PER_FRAME == scale )
585 {
586 return mTotalTimeInFrame;
587 }
588 else
589 {
590 return LLStatAccum::meanValue(scale);
591 }
279} 592}
280 593
281 594
282LLStatTime::LLStatTime(bool use_frame_timer) 595// ------------------------------------------------------------------------
283 : LLStatAccum(use_frame_timer) 596
597
598// Use this constructor for pre-defined LLStatTime objects
599LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL)
284{ 600{
601 if (mPredefinedStat)
602 {
603 // If dynamic stats are turned on, this will create a separate entry in the stat map.
604 initDynamicStat(mPredefinedStat->mKey);
605
606 // Start predefined stats. These stats are not part of the stat map.
607 mPredefinedStat->start();
608 }
285} 609}
286 610
287void LLStatTime::start() 611// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
612// These are also turned on or off via the switch passed in
613LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
288{ 614{
289 m.sum(0.0); 615 if (!sStatsEnabled) return;
616
617 if (NULL == key2 || strlen(key2) == 0)
618 {
619 initDynamicStat(key1);
620 }
621 else
622 {
623 std::ostringstream key;
624 key << key1 << "_" << key2;
625 initDynamicStat(key.str());
626 }
290} 627}
291 628
292void LLStatTime::stop() 629void LLPerfBlock::initDynamicStat(const std::string& key)
630{
631 // Early exit if dynamic stats aren't enabled.
632 if (!sStatsEnabled) return;
633
634 mLastPath = sCurrentStatPath; // Save and restore current path
635 sCurrentStatPath += "/" + key; // Add key to current path
636
637 // See if the LLStatTime object already exists
638 stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath);
639 if ( iter == sStatMap.end() )
640 {
641 // StatEntry object doesn't exist, so create it
642 mDynamicStat = new StatEntry( key );
643 sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path
644 }
645 else
646 {
647 // Found this path in the map, use the object there
648 mDynamicStat = (*iter).second; // Get StatEntry for the current path
649 }
650
651 if (mDynamicStat)
652 {
653 mDynamicStat->mStat.start();
654 mDynamicStat->mCount++;
655 }
656 else
657 {
658 llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl;
659 sCurrentStatPath = mLastPath;
660 }
661}
662
663
664// Destructor does the time accounting
665LLPerfBlock::~LLPerfBlock()
666{
667 if (mPredefinedStat) mPredefinedStat->stop();
668 if (mDynamicStat)
669 {
670 mDynamicStat->mStat.stop();
671 sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block
672 }
673}
674
675
676// Clear the map of any dynamic stats. Static routine
677void LLPerfBlock::clearDynamicStats()
678{
679 std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer());
680 sStatMap.clear();
681}
682
683// static - Extract the stat info into LLSD
684void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
685 LLStatAccum::TimeScale scale )
293{ 686{
294 U64 endTime = m.getCurrentUsecs(); 687 // If we aren't in per-frame scale, we need to go from second to microsecond.
295 m.sum((F64)(endTime - m.mLastTime), endTime); 688 U32 scale_adjustment = 1;
689 if (LLStatAccum::SCALE_PER_FRAME != scale)
690 {
691 scale_adjustment = USEC_PER_SEC;
692 }
693 stat_map_t::iterator iter = sStatMap.begin();
694 for ( ; iter != sStatMap.end(); ++iter )
695 { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time
696 const std::string & stats_full_path = (*iter).first;
697
698 StatEntry * stat = (*iter).second;
699 if (stat)
700 {
701 if (stat->mCount > 0)
702 {
703 stats[stats_full_path] = LLSD::emptyMap();
704 stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale));
705 if (stat->mCount > 1)
706 {
707 stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount;
708 }
709 stat->mCount = 0;
710 }
711 }
712 else
713 { // WTF? Shouldn't have a NULL pointer in the map.
714 llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
715 }
716 }
296} 717}
297 718
298 719
720// ------------------------------------------------------------------------
299 721
300LLTimer LLStat::sTimer; 722LLTimer LLStat::sTimer;
301LLFrameTimer LLStat::sFrameTimer; 723LLFrameTimer LLStat::sFrameTimer;
diff --git a/linden/indra/llcommon/llstat.h b/linden/indra/llcommon/llstat.h
index 0a7e014..63813e2 100644
--- a/linden/indra/llcommon/llstat.h
+++ b/linden/indra/llcommon/llstat.h
@@ -33,9 +33,13 @@
33#define LL_LLSTAT_H 33#define LL_LLSTAT_H
34 34
35#include <deque> 35#include <deque>
36#include <map>
36 37
37#include "lltimer.h" 38#include "lltimer.h"
38#include "llframetimer.h" 39#include "llframetimer.h"
40#include "llfile.h"
41
42class LLSD;
39 43
40// Set this if longer stats are needed 44// Set this if longer stats are needed
41#define ENABLE_LONG_TIME_STATS 0 45#define ENABLE_LONG_TIME_STATS 0
@@ -58,25 +62,50 @@ public:
58 SCALE_100MS, 62 SCALE_100MS,
59 SCALE_SECOND, 63 SCALE_SECOND,
60 SCALE_MINUTE, 64 SCALE_MINUTE,
61 SCALE_TWO_MINUTE,
62#if ENABLE_LONG_TIME_STATS 65#if ENABLE_LONG_TIME_STATS
63 SCALE_HOUR, 66 SCALE_HOUR,
64 SCALE_DAY, 67 SCALE_DAY,
65 SCALE_WEEK, 68 SCALE_WEEK,
66#endif 69#endif
67 NUM_SCALES 70 NUM_SCALES, // Use to size storage arrays
71 SCALE_PER_FRAME // For latest frame information - should be after NUM_SCALES since this doesn't go into the time buckets
68 }; 72 };
69 73
70 F32 meanValue(TimeScale scale) const; 74 static U64 sScaleTimes[NUM_SCALES];
75
76 virtual F32 meanValue(TimeScale scale) const;
71 // see the subclasses for the specific meaning of value 77 // see the subclasses for the specific meaning of value
72 78
73 F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); } 79 F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); }
74 F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); } 80 F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); }
75 F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); } 81 F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); }
76 82
77protected: 83 void reset(U64 when);
78 class impl; 84
79 impl& m; 85 void sum(F64 value);
86 void sum(F64 value, U64 when);
87
88 U64 getCurrentUsecs() const;
89 // Get current microseconds based on timer type
90
91 BOOL mUseFrameTimer;
92 BOOL mRunning;
93
94 U64 mLastTime;
95
96 struct Bucket
97 {
98 F64 accum;
99 U64 endTime;
100
101 BOOL lastValid;
102 F64 lastAccum;
103 };
104
105 Bucket mBuckets[NUM_SCALES];
106
107 BOOL mLastSampleValid;
108 F64 mLastSampleValue;
80}; 109};
81 110
82class LLStatMeasure : public LLStatAccum 111class LLStatMeasure : public LLStatAccum
@@ -105,39 +134,120 @@ public:
105 void count(U32); 134 void count(U32);
106 // used to note that n items have occured 135 // used to note that n items have occured
107 136
108 void mark() { count(1); } 137 void mark();
109 // used for counting the rate thorugh a point in the code 138 // used for counting the rate thorugh a point in the code
110}; 139};
111 140
112 141
113class LLTimeBlock;
114
115class LLStatTime : public LLStatAccum 142class LLStatTime : public LLStatAccum
116 // gathers statistics about time spent in a block of code 143 // gathers statistics about time spent in a block of code
117 // measure average duration per second in the block 144 // measure average duration per second in the block
118{ 145{
119public: 146public:
120 LLStatTime(bool use_frame_timer = false); 147 LLStatTime( const std::string & key = "undefined" );
148
149 U32 mFrameNumber; // Current frame number
150 U64 mTotalTimeInFrame; // Total time (microseconds) accumulated during the last frame
151
152 void setKey( const std::string & key ) { mKey = key; };
153
154 virtual F32 meanValue(TimeScale scale) const;
121 155
122private: 156private:
123 void start(); 157 void start(); // Start and stop measuring time block
124 void stop(); 158 void stop();
125 friend class LLTimeBlock; 159
160 std::string mKey; // Tag representing this time block
161
162#if LL_DEBUG
163 BOOL mRunning; // TRUE if start() has been called
164#endif
165
166 friend class LLPerfBlock;
126}; 167};
127 168
128class LLTimeBlock 169// ----------------------------------------------------------------------------
170
171
172// Use this class on the stack to record statistics about an area of code
173class LLPerfBlock
129{ 174{
130public: 175public:
131 LLTimeBlock(LLStatTime& stat) : mStat(stat) { mStat.start(); } 176 struct StatEntry
132 ~LLTimeBlock() { mStat.stop(); } 177 {
178 StatEntry(const std::string& key) : mStat(LLStatTime(key)), mCount(0) {}
179 LLStatTime mStat;
180 U32 mCount;
181 };
182 typedef std::map<std::string, StatEntry*> stat_map_t;
183
184 // Use this constructor for pre-defined LLStatTime objects
185 LLPerfBlock(LLStatTime* stat);
186
187 // Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
188 LLPerfBlock( const char* key1, const char* key2 = NULL);
189
190
191 ~LLPerfBlock();
192
193 static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
194 static S32 getStatsEnabled() { return sStatsEnabled; };
195
196 static void clearDynamicStats(); // Reset maps to clear out dynamic objects
197 static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
198 LLStatAccum::TimeScale scale );
199
133private: 200private:
134 LLStatTime& mStat; 201 // Initialize dynamically created LLStatTime objects
202 void initDynamicStat(const std::string& key);
203
204 std::string mLastPath; // Save sCurrentStatPath when this is called
205 LLStatTime * mPredefinedStat; // LLStatTime object to get data
206 StatEntry * mDynamicStat; // StatEntryobject to get data
207
208 static BOOL sStatsEnabled; // Normally FALSE
209 static stat_map_t sStatMap; // Map full path string to LLStatTime objects
210 static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
135}; 211};
136 212
213// ----------------------------------------------------------------------------
137 214
215class LLPerfStats
216{
217public:
218 LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
219 virtual ~LLPerfStats();
220
221 virtual void init(); // Reset and start all stat timers
222 virtual void updatePerFrameStats();
223 // Override these function to add process-specific information to the performance log header and per-frame logging.
224 virtual void addProcessHeaderInfo(LLSD& info) { /* not implemented */ }
225 virtual void addProcessFrameInfo(LLSD& info, LLStatAccum::TimeScale scale) { /* not implemented */ }
226
227 // High-resolution frame stats
228 BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
229 F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
230 void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
231 void setReportPerformanceDuration( F32 seconds );
232 void setProcessName(const std::string& process_name) { mProcessName = process_name; }
233 void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
138 234
235protected:
236 void openPerfStatsFile(); // Open file for high resolution metrics logging
237 void dumpIntervalPerformanceStats();
238
239 llofstream mFrameStatsFile; // File for per-frame stats
240 BOOL mFrameStatsFileFailure; // Flag to prevent repeat opening attempts
241 BOOL mSkipFirstFrameStats; // Flag to skip one (partial) frame report
242 std::string mProcessName;
243 S32 mProcessPID;
139 244
245private:
246 F32 mReportPerformanceStatInterval; // Seconds between performance stats
247 F64 mReportPerformanceStatEnd; // End time (seconds) for performance stats
248};
140 249
250// ----------------------------------------------------------------------------
141class LLStat 251class LLStat
142{ 252{
143public: 253public: