# define WIN32_LEAN_AND_MEAN
static const S32 CPUINFO_BUFFER_SIZE = 16383;
+// 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;
typedef struct _DllVersionInfo
+ // Hooking onto the "mainloop" event pump gets us one call per frame.
+ .listen("FrameWatcher", boost::bind(&FrameWatcher::tick, this, _1))),
+ // Initializing mSampleStart to an invalid timestamp alerts us to skip
+ // trying to compute framerate on the first call.
+ // Initializing mSampleEnd to 0 ensures that we treat the first call
+ // as the completion of a sample window.
+ // Initializing to F32_MAX means that the first real frame will become
+ // the slowest ever, which sounds like a good idea.
+ F32 timestamp(mTimer.getElapsedTimeF32());
+ // Count this frame in the interval just completed.
+ // Have we finished a sample window yet?
+ if (timestamp < mSampleEnd)
+ // no, just keep waiting
+ // Set up for next sample window. Capture values for previous frame in
+ // local variables and reset data members.
+ F32 sampleStart(mSampleStart);
+ // No frames yet in next window
+ // which starts right now
+ mSampleStart = timestamp;
+ // and ends MEM_INFO_THROTTLE seconds in the future
+ mSampleEnd = mSampleStart + MEM_INFO_THROTTLE;
+ // On the very first call, that's all we can do, no framerate
+ // computation is possible.
+ // How long did this actually take? As framerate slows, the duration
+ // of the frame we just finished could push us WELL beyond our desired
+ F32 elapsed(timestamp - sampleStart);
+ F32 framerate(frames/elapsed);
+ // 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)
+ // Congratulations, we've hit a new low. :-P
+ LL_INFOS("FrameWatcher") << mDesc << " framerate "
+ << std::fixed << std::setprecision(1) << framerate << '\n'
+ << LLMemoryInfo() << LL_ENDL;
+ // Storing the connection in an LLTempBoundListener ensures it will be
+ // disconnected when we're destroyed.
+ LLTempBoundListener mConnection;
+ // Some of what you see here is in fact redundant with functionality you
+ // can get from LLTimer. Unfortunately the LLTimer API is missing the
+ // feature we need: has at least the stated interval elapsed, and if so,
+ // exactly how long has passed? So we have to do it by hand, sigh.
+ // Time at start, end of sample window
+ F32 mSampleStart, mSampleEnd;
+ // Frames this sample window
+ // Slowest framerate EVAR
+ // Description of next notable framerate
+static FrameWatcher sFrameWatcher;
BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile)