diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llcommon/llstat.cpp | 562 |
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 | ||
37 | class LLStatAccum::impl | 43 | |
44 | // statics | ||
45 | BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information | ||
46 | LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects | ||
47 | std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step" | ||
48 | |||
49 | //------------------------------------------------------------------------ | ||
50 | // Live config file to trigger stats logging | ||
51 | static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd"; | ||
52 | static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds | ||
53 | |||
54 | class LLStatsConfigFile : public LLLiveFile | ||
38 | { | 55 | { |
39 | public: | 56 | public: |
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 | |||
63 | protected: | ||
64 | /* virtual */ void loadFile(); | ||
44 | 65 | ||
45 | BOOL mRunning; | 66 | public: |
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]; | 73 | protected: |
74 | LLPerfStats* mStatsp; | ||
75 | }; | ||
58 | 76 | ||
59 | BOOL mLastSampleValid; | 77 | std::string LLStatsConfigFile::filename() |
60 | F64 mLastSampleValue; | 78 | { |
79 | return STATS_CONFIG_FILE_NAME; | ||
80 | } | ||
61 | 81 | ||
82 | void LLStatsConfigFile::init(LLPerfStats* statsp) | ||
83 | { | ||
84 | mStatsp = statsp; | ||
85 | } | ||
62 | 86 | ||
63 | impl(bool useFrameTimer); | 87 | LLStatsConfigFile& 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 |
96 | void 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 | ||
166 | LLPerfStats::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 | ||
77 | U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] = | 175 | LLPerfStats::~LLPerfStats() |
176 | { | ||
177 | LLPerfBlock::clearDynamicStats(); | ||
178 | mFrameStatsFile.close(); | ||
179 | } | ||
180 | |||
181 | void 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 | ||
189 | void 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 | ||
218 | void 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 | ||
255 | void 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 | |||
274 | void 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 | |||
311 | U64 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 | ||
92 | LLStatAccum::impl::impl(bool useFrameTimer) | 325 | |
326 | LLStatAccum::LLStatAccum(bool useFrameTimer) | ||
327 | : mUseFrameTimer(useFrameTimer), | ||
328 | mRunning(FALSE), | ||
329 | mLastSampleValue(0.0), | ||
330 | mLastSampleValid(FALSE) | ||
331 | { | ||
332 | } | ||
333 | |||
334 | LLStatAccum::~LLStatAccum() | ||
93 | { | 335 | { |
94 | mUseFrameTimer = useFrameTimer; | ||
95 | mRunning = FALSE; | ||
96 | mLastSampleValid = FALSE; | ||
97 | } | 336 | } |
98 | 337 | ||
99 | void LLStatAccum::impl::reset(U64 when) | 338 | |
339 | |||
340 | void 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 | ||
112 | void LLStatAccum::impl::sum(F64 value) | 353 | void LLStatAccum::sum(F64 value) |
113 | { | 354 | { |
114 | sum(value, getCurrentUsecs()); | 355 | sum(value, getCurrentUsecs()); |
115 | } | 356 | } |
116 | 357 | ||
117 | void LLStatAccum::impl::sum(F64 value, U64 when) | 358 | void 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 | ||
176 | F32 LLStatAccum::impl::meanValue(TimeScale scale) const | 418 | F32 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 | ||
212 | U64 LLStatAccum::impl::getCurrentUsecs() const | 459 | U64 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 | 474 | LLStatRate::LLStatRate(bool use_frame_timer) | |
227 | 475 | : LLStatAccum(use_frame_timer) | |
228 | LLStatAccum::LLStatAccum(bool useFrameTimer) | ||
229 | : m(* new impl(useFrameTimer)) | ||
230 | { | 476 | { |
231 | } | 477 | } |
232 | 478 | ||
233 | LLStatAccum::~LLStatAccum() | 479 | void LLStatRate::count(U32 value) |
234 | { | 480 | { |
235 | delete &m; | 481 | sum((F64)value * sScaleTimes[SCALE_SECOND]); |
236 | } | 482 | } |
237 | 483 | ||
238 | F32 LLStatAccum::meanValue(TimeScale scale) const | 484 | |
239 | { | 485 | void 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 | ||
245 | LLStatMeasure::LLStatMeasure(bool use_frame_timer) | 511 | LLStatMeasure::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 | ||
250 | void LLStatMeasure::sample(F64 value) | 516 | void 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 | ||
271 | LLStatRate::LLStatRate(bool use_frame_timer) | 537 | // ------------------------------------------------------------------------ |
272 | : LLStatAccum(use_frame_timer) | 538 | |
539 | LLStatTime::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 | ||
276 | void LLStatRate::count(U32 value) | 550 | void 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 | |||
569 | void 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 | ||
282 | LLStatTime::LLStatTime(bool use_frame_timer) | 595 | // ------------------------------------------------------------------------ |
283 | : LLStatAccum(use_frame_timer) | 596 | |
597 | |||
598 | // Use this constructor for pre-defined LLStatTime objects | ||
599 | LLPerfBlock::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 | ||
287 | void 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 | ||
613 | LLPerfBlock::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 | ||
292 | void LLStatTime::stop() | 629 | void 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 | ||
665 | LLPerfBlock::~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 | ||
677 | void 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 | ||
684 | void 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 | ||
300 | LLTimer LLStat::sTimer; | 722 | LLTimer LLStat::sTimer; |
301 | LLFrameTimer LLStat::sFrameTimer; | 723 | LLFrameTimer LLStat::sFrameTimer; |