summaryrefslogtreecommitdiff
path: root/indra/llcommon/lltracerecording.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/lltracerecording.cpp')
-rw-r--r--indra/llcommon/lltracerecording.cpp636
1 files changed, 636 insertions, 0 deletions
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
new file mode 100644
index 0000000000..c110e64380
--- /dev/null
+++ b/indra/llcommon/lltracerecording.cpp
@@ -0,0 +1,636 @@
+/**
+ * @file lltracesampler.cpp
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lltrace.h"
+#include "llfasttimer.h"
+#include "lltracerecording.h"
+#include "lltracethreadrecorder.h"
+#include "llthread.h"
+
+namespace LLTrace
+{
+
+///////////////////////////////////////////////////////////////////////
+// Recording
+///////////////////////////////////////////////////////////////////////
+
+Recording::Recording()
+: mElapsedSeconds(0),
+ mCountsFloat(new AccumulatorBuffer<CountAccumulator<F64> >()),
+ mMeasurementsFloat(new AccumulatorBuffer<MeasurementAccumulator<F64> >()),
+ mCounts(new AccumulatorBuffer<CountAccumulator<S64> >()),
+ mMeasurements(new AccumulatorBuffer<MeasurementAccumulator<S64> >()),
+ mStackTimers(new AccumulatorBuffer<TimeBlockAccumulator>()),
+ mMemStats(new AccumulatorBuffer<MemStatAccumulator>())
+{}
+
+Recording::Recording( const Recording& other )
+{
+ llassert(other.mCountsFloat.notNull());
+ mSamplingTimer = other.mSamplingTimer;
+ mElapsedSeconds = other.mElapsedSeconds;
+ mCountsFloat = other.mCountsFloat;
+ mMeasurementsFloat = other.mMeasurementsFloat;
+ mCounts = other.mCounts;
+ mMeasurements = other.mMeasurements;
+ mStackTimers = other.mStackTimers;
+ mMemStats = other.mMemStats;
+
+ LLStopWatchControlsMixin<Recording>::initTo(other.getPlayState());
+}
+
+
+Recording::~Recording()
+{
+ stop();
+ llassert(isStopped());
+}
+
+void Recording::update()
+{
+ if (isStarted())
+ {
+ LLTrace::get_thread_recorder()->update(this);
+ mSamplingTimer.reset();
+ }
+}
+
+void Recording::handleReset()
+{
+ mCountsFloat.write()->reset();
+ mMeasurementsFloat.write()->reset();
+ mCounts.write()->reset();
+ mMeasurements.write()->reset();
+ mStackTimers.write()->reset();
+ mMemStats.write()->reset();
+
+ mElapsedSeconds = 0.0;
+ mSamplingTimer.reset();
+}
+
+void Recording::handleStart()
+{
+ mSamplingTimer.reset();
+ LLTrace::get_thread_recorder()->activate(this);
+}
+
+void Recording::handleStop()
+{
+ mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
+ LLTrace::TimeBlock::processTimes();
+ LLTrace::get_thread_recorder()->deactivate(this);
+}
+
+void Recording::handleSplitTo(Recording& other)
+{
+ stop();
+ other.restart();
+ other.mMeasurementsFloat.write()->reset(mMeasurementsFloat);
+ other.mMeasurements.write()->reset(mMeasurements);
+ //TODO: figure out how to get seamless handoff of timing stats
+}
+
+void Recording::makePrimary()
+{
+ mCountsFloat.write()->makePrimary();
+ mMeasurementsFloat.write()->makePrimary();
+ mCounts.write()->makePrimary();
+ mMeasurements.write()->makePrimary();
+ mStackTimers.write()->makePrimary();
+ mMemStats.write()->makePrimary();
+
+ ThreadRecorder* thread_recorder = get_thread_recorder().get();
+ AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = *mStackTimers.write();
+ // update stacktimer parent pointers
+ for (S32 i = 0, end_i = mStackTimers->size(); i < end_i; i++)
+ {
+ TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i);
+ if (tree_node)
+ {
+ timer_accumulator_buffer[i].mParent = tree_node->mParent;
+ }
+ }
+}
+
+bool Recording::isPrimary() const
+{
+ return mCounts->isPrimary();
+}
+
+void Recording::makeUnique()
+{
+ mCountsFloat.makeUnique();
+ mMeasurementsFloat.makeUnique();
+ mCounts.makeUnique();
+ mMeasurements.makeUnique();
+ mStackTimers.makeUnique();
+ mMemStats.makeUnique();
+}
+
+void Recording::appendRecording( const Recording& other )
+{
+ mCountsFloat.write()->addSamples(*other.mCountsFloat);
+ mMeasurementsFloat.write()->addSamples(*other.mMeasurementsFloat);
+ mCounts.write()->addSamples(*other.mCounts);
+ mMeasurements.write()->addSamples(*other.mMeasurements);
+ mMemStats.write()->addSamples(*other.mMemStats);
+
+ mStackTimers.write()->addSamples(*other.mStackTimers);
+ mElapsedSeconds += other.mElapsedSeconds;
+}
+
+void Recording::mergeRecording( const Recording& other)
+{
+ mCountsFloat.write()->addSamples(*other.mCountsFloat);
+ mMeasurementsFloat.write()->addSamples(*other.mMeasurementsFloat);
+ mCounts.write()->addSamples(*other.mCounts);
+ mMeasurements.write()->addSamples(*other.mMeasurements);
+ mMemStats.write()->addSamples(*other.mMemStats);
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mTotalTimeCounter / (F64)LLTrace::TimeBlock::countsPerSecond();
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / (F64)LLTrace::TimeBlock::countsPerSecond();
+}
+
+
+U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
+{
+ return (*mStackTimers)[stat.getIndex()].mCalls;
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mTotalTimeCounter / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
+}
+
+F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
+{
+ return (F32)(*mStackTimers)[stat.getIndex()].mCalls / mElapsedSeconds;
+}
+
+LLUnit<LLUnits::Bytes, U32> Recording::getSum(const TraceType<MemStatAccumulator>& stat) const
+{
+ return (*mMemStats)[stat.getIndex()].mAllocatedCount;
+}
+
+LLUnit<LLUnits::Bytes, F32> Recording::getPerSec(const TraceType<MemStatAccumulator>& stat) const
+{
+ return (F32)(*mMemStats)[stat.getIndex()].mAllocatedCount / mElapsedSeconds;
+}
+
+
+F64 Recording::getSum( const TraceType<CountAccumulator<F64> >& stat ) const
+{
+ return (*mCountsFloat)[stat.getIndex()].getSum();
+}
+
+S64 Recording::getSum( const TraceType<CountAccumulator<S64> >& stat ) const
+{
+ return (*mCounts)[stat.getIndex()].getSum();
+}
+
+F64 Recording::getSum( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (F64)(*mMeasurementsFloat)[stat.getIndex()].getSum();
+}
+
+S64 Recording::getSum( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (S64)(*mMeasurements)[stat.getIndex()].getSum();
+}
+
+
+
+F64 Recording::getPerSec( const TraceType<CountAccumulator<F64> >& stat ) const
+{
+ F64 sum = (*mCountsFloat)[stat.getIndex()].getSum();
+ return (sum != 0.0)
+ ? (sum / mElapsedSeconds)
+ : 0.0;
+}
+
+F64 Recording::getPerSec( const TraceType<CountAccumulator<S64> >& stat ) const
+{
+ S64 sum = (*mCounts)[stat.getIndex()].getSum();
+ return (sum != 0)
+ ? ((F64)sum / mElapsedSeconds)
+ : 0.0;
+}
+
+U32 Recording::getSampleCount( const TraceType<CountAccumulator<F64> >& stat ) const
+{
+ return (*mCountsFloat)[stat.getIndex()].getSampleCount();
+}
+
+U32 Recording::getSampleCount( const TraceType<CountAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getSampleCount();
+}
+
+
+F64 Recording::getPerSec( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ F64 sum = (*mMeasurementsFloat)[stat.getIndex()].getSum();
+ return (sum != 0.0)
+ ? (sum / mElapsedSeconds)
+ : 0.0;
+}
+
+F64 Recording::getPerSec( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ S64 sum = (*mMeasurements)[stat.getIndex()].getSum();
+ return (sum != 0)
+ ? ((F64)sum / mElapsedSeconds)
+ : 0.0;
+}
+
+F64 Recording::getMin( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getMin();
+}
+
+S64 Recording::getMin( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getMin();
+}
+
+F64 Recording::getMax( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getMax();
+}
+
+S64 Recording::getMax( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getMax();
+}
+
+F64 Recording::getMean( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getMean();
+}
+
+F64 Recording::getMean( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getMean();
+}
+
+F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getStandardDeviation();
+}
+
+F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getStandardDeviation();
+}
+
+F64 Recording::getLastValue( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getLastValue();
+}
+
+S64 Recording::getLastValue( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getLastValue();
+}
+
+U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getSampleCount();
+}
+
+U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getSampleCount();
+}
+
+
+
+///////////////////////////////////////////////////////////////////////
+// PeriodicRecording
+///////////////////////////////////////////////////////////////////////
+
+PeriodicRecording::PeriodicRecording( S32 num_periods, EStopWatchState state)
+: mNumPeriods(num_periods),
+ mCurPeriod(0),
+ mTotalValid(false),
+ mRecordingPeriods( new Recording[num_periods])
+{
+ llassert(mNumPeriods > 0);
+ initTo(state);
+}
+
+PeriodicRecording::PeriodicRecording(PeriodicRecording& other)
+: mNumPeriods(other.mNumPeriods),
+ mCurPeriod(other.mCurPeriod),
+ mTotalValid(other.mTotalValid),
+ mTotalRecording(other.mTotalRecording)
+{
+ mRecordingPeriods = new Recording[mNumPeriods];
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ mRecordingPeriods[i] = other.mRecordingPeriods[i];
+ }
+}
+
+
+PeriodicRecording::~PeriodicRecording()
+{
+ delete[] mRecordingPeriods;
+}
+
+
+void PeriodicRecording::nextPeriod()
+{
+ EStopWatchState play_state = getPlayState();
+ Recording& old_recording = getCurRecordingPeriod();
+ mCurPeriod = (mCurPeriod + 1) % mNumPeriods;
+ old_recording.splitTo(getCurRecordingPeriod());
+
+ switch(play_state)
+ {
+ case STOPPED:
+ getCurRecordingPeriod().stop();
+ break;
+ case PAUSED:
+ getCurRecordingPeriod().pause();
+ break;
+ case STARTED:
+ break;
+ }
+ // new period, need to recalculate total
+ mTotalValid = false;
+}
+
+Recording& PeriodicRecording::getTotalRecording()
+{
+ if (!mTotalValid)
+ {
+ mTotalRecording.reset();
+ for (S32 i = mCurPeriod + 1; i < mCurPeriod + mNumPeriods; i++)
+ {
+ mTotalRecording.appendRecording(mRecordingPeriods[i % mNumPeriods]);
+ }
+ }
+ mTotalValid = true;
+ return mTotalRecording;
+}
+
+void PeriodicRecording::start()
+{
+ getCurRecordingPeriod().start();
+}
+
+void PeriodicRecording::stop()
+{
+ getCurRecordingPeriod().stop();
+}
+
+void PeriodicRecording::pause()
+{
+ getCurRecordingPeriod().pause();
+}
+
+void PeriodicRecording::resume()
+{
+ getCurRecordingPeriod().resume();
+}
+
+void PeriodicRecording::restart()
+{
+ getCurRecordingPeriod().restart();
+}
+
+void PeriodicRecording::reset()
+{
+ getCurRecordingPeriod().reset();
+}
+
+void PeriodicRecording::splitTo(PeriodicRecording& other)
+{
+ getCurRecordingPeriod().splitTo(other.getCurRecordingPeriod());
+}
+
+void PeriodicRecording::splitFrom(PeriodicRecording& other)
+{
+ getCurRecordingPeriod().splitFrom(other.getCurRecordingPeriod());
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// ExtendableRecording
+///////////////////////////////////////////////////////////////////////
+
+void ExtendableRecording::extend()
+{
+ mAcceptedRecording.appendRecording(mPotentialRecording);
+ mPotentialRecording.reset();
+}
+
+void ExtendableRecording::start()
+{
+ mPotentialRecording.start();
+}
+
+void ExtendableRecording::stop()
+{
+ mPotentialRecording.stop();
+}
+
+void ExtendableRecording::pause()
+{
+ mPotentialRecording.pause();
+}
+
+void ExtendableRecording::resume()
+{
+ mPotentialRecording.resume();
+}
+
+void ExtendableRecording::restart()
+{
+ mAcceptedRecording.reset();
+ mPotentialRecording.restart();
+}
+
+void ExtendableRecording::reset()
+{
+ mAcceptedRecording.reset();
+ mPotentialRecording.reset();
+}
+
+void ExtendableRecording::splitTo(ExtendableRecording& other)
+{
+ mPotentialRecording.splitTo(other.mPotentialRecording);
+}
+
+void ExtendableRecording::splitFrom(ExtendableRecording& other)
+{
+ mPotentialRecording.splitFrom(other.mPotentialRecording);
+}
+
+PeriodicRecording& get_frame_recording()
+{
+ static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(64, PeriodicRecording::STARTED));
+ return *sRecording;
+}
+
+}
+
+void LLStopWatchControlsMixinCommon::start()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ handleReset();
+ handleStart();
+ break;
+ case PAUSED:
+ handleStart();
+ break;
+ case STARTED:
+ handleReset();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::stop()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ handleStop();
+ break;
+ case STARTED:
+ handleStop();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STOPPED;
+}
+
+void LLStopWatchControlsMixinCommon::pause()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ break;
+ case STARTED:
+ handleStop();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = PAUSED;
+}
+
+void LLStopWatchControlsMixinCommon::resume()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ handleStart();
+ break;
+ case PAUSED:
+ handleStart();
+ break;
+ case STARTED:
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::restart()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ handleReset();
+ handleStart();
+ break;
+ case PAUSED:
+ handleReset();
+ handleStart();
+ break;
+ case STARTED:
+ handleReset();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::reset()
+{
+ handleReset();
+}
+
+void LLStopWatchControlsMixinCommon::initTo( EStopWatchState state )
+{
+ switch(state)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ break;
+ case STARTED:
+ handleStart();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+
+ mState = state;
+}