aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llcommon/llstat.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llcommon/llstat.cpp562
1 files changed, 492 insertions, 70 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;