diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2011-06-28 16:01:16 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2011-06-28 16:01:16 -0400 |
commit | 26be53aede499182252bb797e798611169ea0553 (patch) | |
tree | a0a9491abe3950ea2cacce02f1eb788c738f04ee /indra/llcommon | |
parent | 57c230b73ea171d310ad3c132624a8fdd6751b0e (diff) |
CHOP-753: Introduce a sliding window of framerate samples.
The trouble with remembering the slowest-ever framerate is that framerate
drops dramatically on login, then typically bounces back to something
reasonable during the session. So the session-normal framerate has to drop
pretty dramatically before it falls below the original login framerate. To
address this, only remember the last ~10 minutes of framerates, and log memory
stats every time a new framerate is slower than the previous 10 minutes.
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llsys.cpp | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 156c78b1e8..ccd6f261b7 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -44,6 +44,7 @@ #include "llevents.h" #include "lltimer.h" #include <boost/bind.hpp> +#include <boost/circular_buffer.hpp> #if LL_WINDOWS # define WIN32_LEAN_AND_MEAN @@ -81,6 +82,11 @@ LLCPUInfo gSysCPU; // Don't log memory info any more often than this. It also serves as our // framerate sample size. static const F32 MEM_INFO_THROTTLE = 20; +// Sliding window of samples. We intentionally limit the length of time we +// remember "the slowest" framerate because framerate is very slow at login. +// If we only triggered FrameWatcher logging when the session framerate +// dropped below the login framerate, we'd have very little additional data. +static const F32 MEM_INFO_WINDOW = 10*60; #if LL_WINDOWS #ifndef DLLVERSIONINFO @@ -903,10 +909,13 @@ public: // as the completion of a sample window. mSampleEnd(0), mFrames(0), + // Both MEM_INFO_WINDOW and MEM_INFO_THROTTLE are in seconds. We need + // the number of integer MEM_INFO_THROTTLE sample slots that will fit + // in MEM_INFO_WINDOW. Round up. + mSamples(int((MEM_INFO_WINDOW / MEM_INFO_THROTTLE) + 0.7)), // Initializing to F32_MAX means that the first real frame will become // the slowest ever, which sounds like a good idea. - mSlowest(F32_MAX), - mDesc("startup") + mSlowest(F32_MAX) {} bool tick(const LLSD&) @@ -947,20 +956,54 @@ public: F32 elapsed(timestamp - sampleStart); F32 framerate(frames/elapsed); + // Remember previous slowest framerate because we're just about to + // update it. + F32 slowest(mSlowest); + // Remember previous number of samples. + boost::circular_buffer<F32>::size_type prevSize(mSamples.size()); + + // Capture new framerate in our samples buffer. Once the buffer is + // full (after MEM_INFO_WINDOW seconds), this will displace the oldest + // sample. ("So they all rolled over, and one fell out...") + mSamples.push_back(framerate); + + // Calculate the new minimum framerate. I know of no way to update a + // rolling minimum without ever rescanning the buffer. But since there + // are only a few tens of items in this buffer, rescanning it is + // probably cheaper (and certainly easier to reason about) than + // attempting to optimize away some of the scans. + mSlowest = framerate; // pick an arbitrary entry to start + for (boost::circular_buffer<F32>::const_iterator si(mSamples.begin()), send(mSamples.end()); + si != send; ++si) + { + if (*si < mSlowest) + { + mSlowest = *si; + } + } + // We're especially interested in memory as framerate drops. Only log - // when framerate is lower than ever before. (Should always be true - // for the end of the very first sample window.) - if (framerate >= mSlowest) + // when framerate drops below the slowest framerate we remember. + // (Should always be true for the end of the very first sample + // window.) + if (framerate >= slowest) { return false; } // Congratulations, we've hit a new low. :-P - mSlowest = framerate; - LL_INFOS("FrameWatcher") << mDesc << " framerate " - << std::fixed << std::setprecision(1) << framerate << '\n' - << LLMemoryInfo() << LL_ENDL; - mDesc = "new lowest"; + LL_INFOS("FrameWatcher") << ' '; + if (! prevSize) + { + LL_CONT << "initial framerate "; + } + else + { + LL_CONT << "slowest framerate for last " << int(prevSize * MEM_INFO_THROTTLE) + << " seconds "; + } + LL_CONT << std::fixed << std::setprecision(1) << framerate << '\n' + << LLMemoryInfo() << LL_ENDL; return false; } @@ -979,12 +1022,13 @@ private: F32 mSampleStart, mSampleEnd; // Frames this sample window U32 mFrames; - // Slowest framerate EVAR + // Sliding window of framerate samples + boost::circular_buffer<F32> mSamples; + // Slowest framerate in mSamples F32 mSlowest; - // Description of next notable framerate - std::string mDesc; }; +// Need an instance of FrameWatcher before it does any good static FrameWatcher sFrameWatcher; BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) |