00001
00031 #include "linden_common.h"
00032
00033 #include "llstat.h"
00034 #include "llframetimer.h"
00035 #include "timing.h"
00036
00037 class LLStatAccum::impl
00038 {
00039 public:
00040 static const TimeScale IMPL_NUM_SCALES = (TimeScale)(SCALE_TWO_MINUTE + 1);
00041 static U64 sScaleTimes[IMPL_NUM_SCALES];
00042
00043 BOOL mUseFrameTimer;
00044
00045 BOOL mRunning;
00046 U64 mLastTime;
00047
00048 struct Bucket
00049 {
00050 F64 accum;
00051 U64 endTime;
00052
00053 BOOL lastValid;
00054 F64 lastAccum;
00055 };
00056
00057 Bucket mBuckets[IMPL_NUM_SCALES];
00058
00059 BOOL mLastSampleValid;
00060 F64 mLastSampleValue;
00061
00062
00063 impl(bool useFrameTimer);
00064
00065 void reset(U64 when);
00066
00067 void sum(F64 value);
00068 void sum(F64 value, U64 when);
00069
00070 F32 meanValue(TimeScale scale) const;
00071
00072 U64 getCurrentUsecs() const;
00073
00074 };
00075
00076
00077 U64 LLStatAccum::impl::sScaleTimes[IMPL_NUM_SCALES] =
00078 {
00079 USEC_PER_SEC * 1,
00080 USEC_PER_SEC * 60,
00081 USEC_PER_SEC * 60 * 2
00082 #if 0
00083
00084 USEC_PER_SEC * 60*60,
00085 USEC_PER_SEC * 24*60*60,
00086 USEC_PER_SEC * 7*24*60*60,
00087 #endif
00088 };
00089
00090
00091 LLStatAccum::impl::impl(bool useFrameTimer)
00092 {
00093 mUseFrameTimer = useFrameTimer;
00094 mRunning = FALSE;
00095 mLastSampleValid = FALSE;
00096 }
00097
00098 void LLStatAccum::impl::reset(U64 when)
00099 {
00100 mRunning = TRUE;
00101 mLastTime = when;
00102
00103 for (int i = 0; i < IMPL_NUM_SCALES; ++i)
00104 {
00105 mBuckets[i].accum = 0.0;
00106 mBuckets[i].endTime = when + sScaleTimes[i];
00107 mBuckets[i].lastValid = FALSE;
00108 }
00109 }
00110
00111 void LLStatAccum::impl::sum(F64 value)
00112 {
00113 sum(value, getCurrentUsecs());
00114 }
00115
00116 void LLStatAccum::impl::sum(F64 value, U64 when)
00117 {
00118 if (!mRunning)
00119 {
00120 reset(when);
00121 return;
00122 }
00123 if (when < mLastTime)
00124 {
00125
00126 lldebugs << "LLStatAccum::sum clock has gone backwards from "
00127 << mLastTime << " to " << when << ", resetting" << llendl;
00128
00129 reset(when);
00130 return;
00131 }
00132
00133 for (int i = 0; i < IMPL_NUM_SCALES; ++i)
00134 {
00135 Bucket& bucket = mBuckets[i];
00136
00137 if (when < bucket.endTime)
00138 {
00139 bucket.accum += value;
00140 }
00141 else
00142 {
00143 U64 timeScale = sScaleTimes[i];
00144
00145 U64 timeSpan = when - mLastTime;
00146
00147 U64 timeLeft = when - bucket.endTime;
00148
00149
00150 if (timeLeft < timeScale)
00151 {
00152 F64 valueLeft = value * timeLeft / timeSpan;
00153
00154 bucket.lastValid = TRUE;
00155 bucket.lastAccum = bucket.accum + (value - valueLeft);
00156 bucket.accum = valueLeft;
00157 bucket.endTime += timeScale;
00158 }
00159 else
00160 {
00161 U64 timeTail = timeLeft % timeScale;
00162
00163 bucket.lastValid = TRUE;
00164 bucket.lastAccum = value * timeScale / timeSpan;
00165 bucket.accum = value * timeTail / timeSpan;
00166 bucket.endTime += (timeLeft - timeTail) + timeScale;
00167 }
00168 }
00169 }
00170
00171 mLastTime = when;
00172 }
00173
00174
00175 F32 LLStatAccum::impl::meanValue(TimeScale scale) const
00176 {
00177 if (!mRunning)
00178 {
00179 return 0.0;
00180 }
00181 if (scale < 0 || scale >= IMPL_NUM_SCALES)
00182 {
00183 llwarns << "llStatAccum::meanValue called for unsupported scale: "
00184 << scale << llendl;
00185 return 0.0;
00186 }
00187
00188 const Bucket& bucket = mBuckets[scale];
00189
00190 F64 value = bucket.accum;
00191 U64 timeLeft = bucket.endTime - mLastTime;
00192 U64 scaleTime = sScaleTimes[scale];
00193
00194 if (bucket.lastValid)
00195 {
00196 value += bucket.lastAccum * timeLeft / scaleTime;
00197 }
00198 else if (timeLeft < scaleTime)
00199 {
00200 value *= scaleTime / (scaleTime - timeLeft);
00201 }
00202 else
00203 {
00204 value = 0.0;
00205 }
00206
00207 return (F32)(value / scaleTime);
00208 }
00209
00210
00211 U64 LLStatAccum::impl::getCurrentUsecs() const
00212 {
00213 if (mUseFrameTimer)
00214 {
00215 return LLFrameTimer::getTotalTime();
00216 }
00217 else
00218 {
00219 return totalTime();
00220 }
00221 }
00222
00223
00224
00225
00226
00227 LLStatAccum::LLStatAccum(bool useFrameTimer)
00228 : m(* new impl(useFrameTimer))
00229 {
00230 }
00231
00232 LLStatAccum::~LLStatAccum()
00233 {
00234 delete &m;
00235 }
00236
00237 F32 LLStatAccum::meanValue(TimeScale scale) const
00238 {
00239 return m.meanValue(scale);
00240 }
00241
00242
00243
00244 LLStatMeasure::LLStatMeasure(bool use_frame_timer)
00245 : LLStatAccum(use_frame_timer)
00246 {
00247 }
00248
00249 void LLStatMeasure::sample(F64 value)
00250 {
00251 U64 when = m.getCurrentUsecs();
00252
00253 if (m.mLastSampleValid)
00254 {
00255 F64 avgValue = (value + m.mLastSampleValue) / 2.0;
00256 F64 interval = (F64)(when - m.mLastTime);
00257
00258 m.sum(avgValue * interval, when);
00259 }
00260 else
00261 {
00262 m.reset(when);
00263 }
00264
00265 m.mLastSampleValid = TRUE;
00266 m.mLastSampleValue = value;
00267 }
00268
00269
00270 LLStatRate::LLStatRate(bool use_frame_timer)
00271 : LLStatAccum(use_frame_timer)
00272 {
00273 }
00274
00275 void LLStatRate::count(U32 value)
00276 {
00277 m.sum((F64)value * impl::sScaleTimes[SCALE_SECOND]);
00278 }
00279
00280
00281 LLStatTime::LLStatTime(bool use_frame_timer)
00282 : LLStatAccum(use_frame_timer)
00283 {
00284 }
00285
00286 void LLStatTime::start()
00287 {
00288 m.sum(0.0);
00289 }
00290
00291 void LLStatTime::stop()
00292 {
00293 U64 endTime = m.getCurrentUsecs();
00294 m.sum((F64)(endTime - m.mLastTime), endTime);
00295 }
00296
00297
00298
00299 LLTimer LLStat::sTimer;
00300 LLFrameTimer LLStat::sFrameTimer;
00301
00302 LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
00303 {
00304 llassert(num_bins > 0);
00305 U32 i;
00306 mUseFrameTimer = use_frame_timer;
00307 mNumValues = 0;
00308 mLastValue = 0.f;
00309 mLastTime = 0.f;
00310 mNumBins = num_bins;
00311 mCurBin = (mNumBins-1);
00312 mNextBin = 0;
00313 mBins = new F32[mNumBins];
00314 mBeginTime = new F64[mNumBins];
00315 mTime = new F64[mNumBins];
00316 mDT = new F32[mNumBins];
00317 for (i = 0; i < mNumBins; i++)
00318 {
00319 mBins[i] = 0.f;
00320 mBeginTime[i] = 0.0;
00321 mTime[i] = 0.0;
00322 mDT[i] = 0.f;
00323 }
00324 }
00325
00326 LLStat::~LLStat()
00327 {
00328 delete[] mBins;
00329 delete[] mBeginTime;
00330 delete[] mTime;
00331 delete[] mDT;
00332 }
00333
00334 void LLStat::reset()
00335 {
00336 U32 i;
00337
00338 mNumValues = 0;
00339 mLastValue = 0.f;
00340 mCurBin = (mNumBins-1);
00341 delete[] mBins;
00342 delete[] mBeginTime;
00343 delete[] mTime;
00344 delete[] mDT;
00345 mBins = new F32[mNumBins];
00346 mBeginTime = new F64[mNumBins];
00347 mTime = new F64[mNumBins];
00348 mDT = new F32[mNumBins];
00349 for (i = 0; i < mNumBins; i++)
00350 {
00351 mBins[i] = 0.f;
00352 mBeginTime[i] = 0.0;
00353 mTime[i] = 0.0;
00354 mDT[i] = 0.f;
00355 }
00356 }
00357
00358 void LLStat::setBeginTime(const F64 time)
00359 {
00360 mBeginTime[mNextBin] = time;
00361 }
00362
00363 void LLStat::addValueTime(const F64 time, const F32 value)
00364 {
00365 if (mNumValues < mNumBins)
00366 {
00367 mNumValues++;
00368 }
00369
00370
00371 mCurBin++;
00372 if ((U32)mCurBin == mNumBins)
00373 {
00374 mCurBin = 0;
00375 }
00376 mNextBin++;
00377 if ((U32)mNextBin == mNumBins)
00378 {
00379 mNextBin = 0;
00380 }
00381
00382 mBins[mCurBin] = value;
00383 mTime[mCurBin] = time;
00384 mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]);
00385
00386 mLastTime = mTime[mCurBin];
00387 mLastValue = value;
00388
00389
00390 mBeginTime[mNextBin] = mTime[mCurBin];
00391 mTime[mNextBin] = mTime[mCurBin];
00392 mDT[mNextBin] = 0.f;
00393 }
00394
00395 void LLStat::start()
00396 {
00397 if (mUseFrameTimer)
00398 {
00399 mBeginTime[mNextBin] = sFrameTimer.getElapsedSeconds();
00400 }
00401 else
00402 {
00403 mBeginTime[mNextBin] = sTimer.getElapsedTimeF64();
00404 }
00405 }
00406
00407 void LLStat::addValue(const F32 value)
00408 {
00409 if (mNumValues < mNumBins)
00410 {
00411 mNumValues++;
00412 }
00413
00414
00415 mCurBin++;
00416 if ((U32)mCurBin == mNumBins)
00417 {
00418 mCurBin = 0;
00419 }
00420 mNextBin++;
00421 if ((U32)mNextBin == mNumBins)
00422 {
00423 mNextBin = 0;
00424 }
00425
00426 mBins[mCurBin] = value;
00427 if (mUseFrameTimer)
00428 {
00429 mTime[mCurBin] = sFrameTimer.getElapsedSeconds();
00430 }
00431 else
00432 {
00433 mTime[mCurBin] = sTimer.getElapsedTimeF64();
00434 }
00435 mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]);
00436
00437
00438 mLastTime = mTime[mCurBin];
00439 mLastValue = value;
00440
00441
00442 mBeginTime[mNextBin] = mTime[mCurBin];
00443 mTime[mNextBin] = mTime[mCurBin];
00444 mDT[mNextBin] = 0.f;
00445 }
00446
00447
00448 F32 LLStat::getMax() const
00449 {
00450 U32 i;
00451 F32 current_max = mLastValue;
00452 if (mNumBins == 0)
00453 {
00454 current_max = 0.f;
00455 }
00456 else
00457 {
00458 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00459 {
00460
00461 if (i == (U32)mNextBin)
00462 {
00463 continue;
00464 }
00465 if (mBins[i] > current_max)
00466 {
00467 current_max = mBins[i];
00468 }
00469 }
00470 }
00471 return current_max;
00472 }
00473
00474 F32 LLStat::getMean() const
00475 {
00476 U32 i;
00477 F32 current_mean = 0.f;
00478 U32 samples = 0;
00479 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00480 {
00481
00482 if (i == (U32)mNextBin)
00483 {
00484 continue;
00485 }
00486 current_mean += mBins[i];
00487 samples++;
00488 }
00489
00490
00491 if (samples != 0)
00492 {
00493 current_mean /= samples;
00494 }
00495 else
00496 {
00497 current_mean = 0.f;
00498 }
00499 return current_mean;
00500 }
00501
00502 F32 LLStat::getMin() const
00503 {
00504 U32 i;
00505 F32 current_min = mLastValue;
00506
00507 if (mNumBins == 0)
00508 {
00509 current_min = 0.f;
00510 }
00511 else
00512 {
00513 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00514 {
00515
00516 if (i == (U32)mNextBin)
00517 {
00518 continue;
00519 }
00520 if (mBins[i] < current_min)
00521 {
00522 current_min = mBins[i];
00523 }
00524 }
00525 }
00526 return current_min;
00527 }
00528
00529 F32 LLStat::getSum() const
00530 {
00531 U32 i;
00532 F32 sum = 0.f;
00533 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00534 {
00535
00536 if (i == (U32)mNextBin)
00537 {
00538 continue;
00539 }
00540 sum += mBins[i];
00541 }
00542
00543 return sum;
00544 }
00545
00546 F32 LLStat::getSumDuration() const
00547 {
00548 U32 i;
00549 F32 sum = 0.f;
00550 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00551 {
00552
00553 if (i == (U32)mNextBin)
00554 {
00555 continue;
00556 }
00557 sum += mDT[i];
00558 }
00559
00560 return sum;
00561 }
00562
00563 F32 LLStat::getPrev(S32 age) const
00564 {
00565 S32 bin;
00566 bin = mCurBin - age;
00567
00568 while (bin < 0)
00569 {
00570 bin += mNumBins;
00571 }
00572
00573 if (bin == mNextBin)
00574 {
00575
00576 return 0.f;
00577 }
00578 return mBins[bin];
00579 }
00580
00581 F32 LLStat::getPrevPerSec(S32 age) const
00582 {
00583 S32 bin;
00584 bin = mCurBin - age;
00585
00586 while (bin < 0)
00587 {
00588 bin += mNumBins;
00589 }
00590
00591 if (bin == mNextBin)
00592 {
00593
00594 return 0.f;
00595 }
00596 return mBins[bin] / mDT[bin];
00597 }
00598
00599 F64 LLStat::getPrevBeginTime(S32 age) const
00600 {
00601 S32 bin;
00602 bin = mCurBin - age;
00603
00604 while (bin < 0)
00605 {
00606 bin += mNumBins;
00607 }
00608
00609 if (bin == mNextBin)
00610 {
00611
00612 return 0.f;
00613 }
00614
00615 return mBeginTime[bin];
00616 }
00617
00618 F64 LLStat::getPrevTime(S32 age) const
00619 {
00620 S32 bin;
00621 bin = mCurBin - age;
00622
00623 while (bin < 0)
00624 {
00625 bin += mNumBins;
00626 }
00627
00628 if (bin == mNextBin)
00629 {
00630
00631 return 0.f;
00632 }
00633
00634 return mTime[bin];
00635 }
00636
00637 F32 LLStat::getBin(S32 bin) const
00638 {
00639 return mBins[bin];
00640 }
00641
00642 F32 LLStat::getBinPerSec(S32 bin) const
00643 {
00644 return mBins[bin] / mDT[bin];
00645 }
00646
00647 F64 LLStat::getBinBeginTime(S32 bin) const
00648 {
00649 return mBeginTime[bin];
00650 }
00651
00652 F64 LLStat::getBinTime(S32 bin) const
00653 {
00654 return mTime[bin];
00655 }
00656
00657 F32 LLStat::getCurrent() const
00658 {
00659 return mBins[mCurBin];
00660 }
00661
00662 F32 LLStat::getCurrentPerSec() const
00663 {
00664 return mBins[mCurBin] / mDT[mCurBin];
00665 }
00666
00667 F64 LLStat::getCurrentBeginTime() const
00668 {
00669 return mBeginTime[mCurBin];
00670 }
00671
00672 F64 LLStat::getCurrentTime() const
00673 {
00674 return mTime[mCurBin];
00675 }
00676
00677 F32 LLStat::getCurrentDuration() const
00678 {
00679 return mDT[mCurBin];
00680 }
00681
00682 F32 LLStat::getMeanPerSec() const
00683 {
00684 U32 i;
00685 F32 value = 0.f;
00686 F32 dt = 0.f;
00687
00688 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00689 {
00690
00691 if (i == (U32)mNextBin)
00692 {
00693 continue;
00694 }
00695 value += mBins[i];
00696 dt += mDT[i];
00697 }
00698
00699 if (dt > 0.f)
00700 {
00701 return value/dt;
00702 }
00703 else
00704 {
00705 return 0.f;
00706 }
00707 }
00708
00709 F32 LLStat::getMeanDuration() const
00710 {
00711 F32 dur = 0.0f;
00712 U32 count = 0;
00713 for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++)
00714 {
00715 if (i == (U32)mNextBin)
00716 {
00717 continue;
00718 }
00719 dur += mDT[i];
00720 count++;
00721 }
00722
00723 if (count > 0)
00724 {
00725 dur /= F32(count);
00726 return dur;
00727 }
00728 else
00729 {
00730 return 0.f;
00731 }
00732 }
00733
00734 F32 LLStat::getMaxPerSec() const
00735 {
00736 U32 i;
00737 F32 value;
00738
00739 if (mNextBin != 0)
00740 {
00741 value = mBins[0]/mDT[0];
00742 }
00743 else if (mNumValues > 0)
00744 {
00745 value = mBins[1]/mDT[1];
00746 }
00747 else
00748 {
00749 value = 0.f;
00750 }
00751
00752 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00753 {
00754
00755 if (i == (U32)mNextBin)
00756 {
00757 continue;
00758 }
00759 value = llmax(value, mBins[i]/mDT[i]);
00760 }
00761 return value;
00762 }
00763
00764 F32 LLStat::getMinPerSec() const
00765 {
00766 U32 i;
00767 F32 value;
00768
00769 if (mNextBin != 0)
00770 {
00771 value = mBins[0]/mDT[0];
00772 }
00773 else if (mNumValues > 0)
00774 {
00775 value = mBins[1]/mDT[1];
00776 }
00777 else
00778 {
00779 value = 0.f;
00780 }
00781
00782 for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
00783 {
00784
00785 if (i == (U32)mNextBin)
00786 {
00787 continue;
00788 }
00789 value = llmin(value, mBins[i]/mDT[i]);
00790 }
00791 return value;
00792 }
00793
00794 F32 LLStat::getMinDuration() const
00795 {
00796 F32 dur = 0.0f;
00797 for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++)
00798 {
00799 dur = llmin(dur, mDT[i]);
00800 }
00801 return dur;
00802 }
00803
00804 U32 LLStat::getNumValues() const
00805 {
00806 return mNumValues;
00807 }
00808
00809 S32 LLStat::getNumBins() const
00810 {
00811 return mNumBins;
00812 }
00813
00814 S32 LLStat::getCurBin() const
00815 {
00816 return mCurBin;
00817 }
00818
00819 S32 LLStat::getNextBin() const
00820 {
00821 return mNextBin;
00822 }
00823
00824 F64 LLStat::getLastTime() const
00825 {
00826 return mLastTime;
00827 }