diff options
author | Richard Linden <none@none> | 2013-06-05 19:05:43 -0700 |
---|---|---|
committer | Richard Linden <none@none> | 2013-06-05 19:05:43 -0700 |
commit | 0a96b47663c99914c587cdcb8bcdc096bbf55fa3 (patch) | |
tree | 67bca4958927ed7f6df423de05e42cd271292391 /indra/llcommon/lltracerecording.cpp | |
parent | dcfb18373eca7986a73d8b9a1d34970cc0a23ed9 (diff) | |
parent | a74b5dfa923f8eeccc9b786143f0f832de3ad450 (diff) |
merge with viewer-release
Diffstat (limited to 'indra/llcommon/lltracerecording.cpp')
-rw-r--r-- | indra/llcommon/lltracerecording.cpp | 944 |
1 files changed, 944 insertions, 0 deletions
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp new file mode 100644 index 0000000000..d32504b014 --- /dev/null +++ b/indra/llcommon/lltracerecording.cpp @@ -0,0 +1,944 @@ +/** + * @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 +{ + + +/////////////////////////////////////////////////////////////////////// +// RecordingBuffers +/////////////////////////////////////////////////////////////////////// + +RecordingBuffers::RecordingBuffers() +{} + +void RecordingBuffers::handOffTo(RecordingBuffers& other) +{ + other.mCounts.reset(&mCounts); + other.mSamples.reset(&mSamples); + other.mEvents.reset(&mEvents); + other.mStackTimers.reset(&mStackTimers); + other.mMemStats.reset(&mMemStats); +} + +void RecordingBuffers::makePrimary() +{ + mCounts.makePrimary(); + mSamples.makePrimary(); + mEvents.makePrimary(); + mStackTimers.makePrimary(); + mMemStats.makePrimary(); + + ThreadRecorder* thread_recorder = get_thread_recorder().get(); + AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers; + // 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 RecordingBuffers::isPrimary() const +{ + return mCounts.isPrimary(); +} + +void RecordingBuffers::append( const RecordingBuffers& other ) +{ + mCounts.addSamples(other.mCounts); + mSamples.addSamples(other.mSamples); + mEvents.addSamples(other.mEvents); + mMemStats.addSamples(other.mMemStats); + mStackTimers.addSamples(other.mStackTimers); +} + +void RecordingBuffers::merge( const RecordingBuffers& other) +{ + mCounts.addSamples(other.mCounts, false); + mSamples.addSamples(other.mSamples, false); + mEvents.addSamples(other.mEvents, false); + mMemStats.addSamples(other.mMemStats, false); + // for now, hold out timers from merge, need to be displayed per thread + //mStackTimers.addSamples(other.mStackTimers, false); +} + +void RecordingBuffers::reset(RecordingBuffers* other) +{ + mCounts.reset(other ? &other->mCounts : NULL); + mSamples.reset(other ? &other->mSamples : NULL); + mEvents.reset(other ? &other->mEvents : NULL); + mStackTimers.reset(other ? &other->mStackTimers : NULL); + mMemStats.reset(other ? &other->mMemStats : NULL); +} + +void RecordingBuffers::flush() +{ + mSamples.flush(); +} + +/////////////////////////////////////////////////////////////////////// +// Recording +/////////////////////////////////////////////////////////////////////// + +Recording::Recording() +: mElapsedSeconds(0) +{ + mBuffers = new RecordingBuffers(); +} + +Recording::Recording( const Recording& other ) +{ + // this will allow us to seamlessly start without affecting any data we've acquired from other + setPlayState(PAUSED); + + Recording& mutable_other = const_cast<Recording&>(other); + EPlayState other_play_state = other.getPlayState(); + mutable_other.pause(); + + mBuffers = other.mBuffers; + + LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state); + mutable_other.setPlayState(other_play_state); + + // above call will clear mElapsedSeconds as a side effect, so copy it here + mElapsedSeconds = other.mElapsedSeconds; + mSamplingTimer = other.mSamplingTimer; +} + + +Recording::~Recording() +{ + if (isStarted() && LLTrace::get_thread_recorder().notNull()) + { + LLTrace::get_thread_recorder()->deactivate(this); + } +} + +void Recording::update() +{ + if (isStarted()) + { + mBuffers.write()->flush(); + LLTrace::get_thread_recorder()->bringUpToDate(this); + mSamplingTimer.reset(); + } +} + +void Recording::handleReset() +{ + mBuffers.write()->reset(); + + mElapsedSeconds = 0.0; + mSamplingTimer.reset(); +} + +void Recording::handleStart() +{ + mSamplingTimer.reset(); + LLTrace::get_thread_recorder()->activate(this); +} + +void Recording::handleStop() +{ + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + mBuffers.write()->flush(); + LLTrace::get_thread_recorder()->deactivate(this); +} + +void Recording::handleSplitTo(Recording& other) +{ + mBuffers.write()->handOffTo(*other.mBuffers.write()); +} + +void Recording::appendRecording( const Recording& other ) +{ + EPlayState play_state = getPlayState(); + { + pause(); + mBuffers.write()->append(*other.mBuffers); + mElapsedSeconds += other.mElapsedSeconds; + } + setPlayState(play_state); +} + +void Recording::mergeRecording( const Recording& other) +{ + EPlayState play_state = getPlayState(); + { + pause(); + mBuffers.write()->merge(*other.mBuffers); + } + setPlayState(play_state); +} + +LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + update(); + return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter) + / (F64)LLTrace::TimeBlock::countsPerSecond(); +} + +LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + update(); + return (F64)(accumulator.mSelfTimeCounter) / (F64)LLTrace::TimeBlock::countsPerSecond(); +} + + +U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat) +{ + update(); + return mBuffers->mStackTimers[stat.getIndex()].mCalls; +} + +LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + + update(); + return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter) + / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds); +} + +LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + + update(); + return (F64)(accumulator.mSelfTimeCounter) + / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds); +} + +F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat) +{ + update(); + return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds; +} + +LLUnit<LLUnits::Bytes, F64> Recording::getMin(const TraceType<MemStatAccumulator>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mSize.getMin(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getMean(const TraceType<MemStatAccumulator>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mSize.getMean(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getMax(const TraceType<MemStatAccumulator>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mSize.getMax(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getStandardDeviation(const TraceType<MemStatAccumulator>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mSize.getStandardDeviation(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getLastValue(const TraceType<MemStatAccumulator>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mSize.getLastValue(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMin(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMean(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMax(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getStandardDeviation(); +} + +LLUnit<LLUnits::Bytes, F64> Recording::getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getLastValue(); +} + +U32 Recording::getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount; +} + +U32 Recording::getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat) +{ + update(); + return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount; +} + + +F64 Recording::getSum( const TraceType<CountAccumulator>& stat ) +{ + update(); + return mBuffers->mCounts[stat.getIndex()].getSum(); +} + +F64 Recording::getSum( const TraceType<EventAccumulator>& stat ) +{ + update(); + return (F64)mBuffers->mEvents[stat.getIndex()].getSum(); +} + +F64 Recording::getPerSec( const TraceType<CountAccumulator>& stat ) +{ + update(); + F64 sum = mBuffers->mCounts[stat.getIndex()].getSum(); + return (sum != 0.0) + ? (sum / mElapsedSeconds) + : 0.0; +} + +U32 Recording::getSampleCount( const TraceType<CountAccumulator>& stat ) +{ + update(); + return mBuffers->mCounts[stat.getIndex()].getSampleCount(); +} + +F64 Recording::getMin( const TraceType<SampleAccumulator>& stat ) +{ + update(); + return mBuffers->mSamples[stat.getIndex()].getMin(); +} + +F64 Recording::getMax( const TraceType<SampleAccumulator>& stat ) +{ + update(); + return mBuffers->mSamples[stat.getIndex()].getMax(); +} + +F64 Recording::getMean( const TraceType<SampleAccumulator>& stat ) +{ + update(); + return mBuffers->mSamples[stat.getIndex()].getMean(); +} + +F64 Recording::getStandardDeviation( const TraceType<SampleAccumulator>& stat ) +{ + update(); + return mBuffers->mSamples[stat.getIndex()].getStandardDeviation(); +} + +F64 Recording::getLastValue( const TraceType<SampleAccumulator>& stat ) +{ + update(); + return mBuffers->mSamples[stat.getIndex()].getLastValue(); +} + +U32 Recording::getSampleCount( const TraceType<SampleAccumulator>& stat ) +{ + update(); + return mBuffers->mSamples[stat.getIndex()].getSampleCount(); +} + +F64 Recording::getMin( const TraceType<EventAccumulator>& stat ) +{ + update(); + return mBuffers->mEvents[stat.getIndex()].getMin(); +} + +F64 Recording::getMax( const TraceType<EventAccumulator>& stat ) +{ + update(); + return mBuffers->mEvents[stat.getIndex()].getMax(); +} + +F64 Recording::getMean( const TraceType<EventAccumulator>& stat ) +{ + update(); + return mBuffers->mEvents[stat.getIndex()].getMean(); +} + +F64 Recording::getStandardDeviation( const TraceType<EventAccumulator>& stat ) +{ + update(); + return mBuffers->mEvents[stat.getIndex()].getStandardDeviation(); +} + +F64 Recording::getLastValue( const TraceType<EventAccumulator>& stat ) +{ + update(); + return mBuffers->mEvents[stat.getIndex()].getLastValue(); +} + +U32 Recording::getSampleCount( const TraceType<EventAccumulator>& stat ) +{ + update(); + return mBuffers->mEvents[stat.getIndex()].getSampleCount(); +} + +/////////////////////////////////////////////////////////////////////// +// PeriodicRecording +/////////////////////////////////////////////////////////////////////// + +PeriodicRecording::PeriodicRecording( U32 num_periods, EPlayState state) +: mAutoResize(num_periods == 0), + mCurPeriod(0), + mRecordingPeriods(num_periods ? num_periods : 1) +{ + setPlayState(state); +} + +void PeriodicRecording::nextPeriod() +{ + if (mAutoResize) + { + mRecordingPeriods.push_back(Recording()); + } + + Recording& old_recording = getCurRecording(); + + mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size(); + old_recording.splitTo(getCurRecording()); +} + + +void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) +{ + if (other.mRecordingPeriods.empty()) return; + + EPlayState play_state = getPlayState(); + pause(); + + EPlayState other_play_state = other.getPlayState(); + other.pause(); + + U32 other_recording_count = other.mRecordingPeriods.size(); + + Recording& other_oldest_recording = other.mRecordingPeriods[(other.mCurPeriod + 1) % other.mRecordingPeriods.size()]; + + // if I have a recording of any length, then close it off and start a fresh one + if (getCurRecording().getDuration().value()) + { + nextPeriod(); + } + getCurRecording().appendRecording(other_oldest_recording); + + if (other_recording_count > 1) + { + if (mAutoResize) + { + for (S32 other_index = (other.mCurPeriod + 2) % other_recording_count, + end_index = (other.mCurPeriod + 1) % other_recording_count; + other_index != end_index; + other_index = (other_index + 1) % other_recording_count) + { + llassert(other.mRecordingPeriods[other_index].getDuration() != 0.f + && (mRecordingPeriods.empty() + || other.mRecordingPeriods[other_index].getDuration() != mRecordingPeriods.back().getDuration())); + mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); + } + + mCurPeriod = mRecordingPeriods.size() - 1; + } + else + { + size_t num_to_copy = llmin( mRecordingPeriods.size(), other.mRecordingPeriods.size() - 1); + std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin() + + ( (other.mCurPeriod + 1 // oldest period + + (other.mRecordingPeriods.size() - num_to_copy)) // minus room for copy + % other.mRecordingPeriods.size()); + std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + ((mCurPeriod + 1) % mRecordingPeriods.size()); + + for(S32 i = 0; i < num_to_copy; i++) + { + *dest_it = *src_it; + + if (++src_it == other.mRecordingPeriods.end()) + { + src_it = other.mRecordingPeriods.begin(); + } + + if (++dest_it == mRecordingPeriods.end()) + { + dest_it = mRecordingPeriods.begin(); + } + } + + mCurPeriod = (mCurPeriod + num_to_copy) % mRecordingPeriods.size(); + } + } + + nextPeriod(); + + setPlayState(play_state); + other.setPlayState(other_play_state); +} + +LLUnit<LLUnits::Seconds, F64> PeriodicRecording::getDuration() const +{ + LLUnit<LLUnits::Seconds, F64> duration; + size_t num_periods = mRecordingPeriods.size(); + for (size_t i = 1; i <= num_periods; i++) + { + size_t index = (mCurPeriod + num_periods - i) % num_periods; + duration += mRecordingPeriods[index].getDuration(); + } + return duration; +} + + +LLTrace::Recording PeriodicRecording::snapshotCurRecording() const +{ + Recording recording_copy(getCurRecording()); + recording_copy.stop(); + return recording_copy; +} + + +Recording& PeriodicRecording::getLastRecording() +{ + return getPrevRecording(1); +} + +const Recording& PeriodicRecording::getLastRecording() const +{ + return getPrevRecording(1); +} + +Recording& PeriodicRecording::getCurRecording() +{ + return mRecordingPeriods[mCurPeriod]; +} + +const Recording& PeriodicRecording::getCurRecording() const +{ + return mRecordingPeriods[mCurPeriod]; +} + +Recording& PeriodicRecording::getPrevRecording( U32 offset ) +{ + U32 num_periods = mRecordingPeriods.size(); + offset = llclamp(offset, 0u, num_periods - 1); + return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; +} + +const Recording& PeriodicRecording::getPrevRecording( U32 offset ) const +{ + U32 num_periods = mRecordingPeriods.size(); + offset = llclamp(offset, 0u, num_periods - 1); + return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; +} + +void PeriodicRecording::handleStart() +{ + getCurRecording().start(); +} + +void PeriodicRecording::handleStop() +{ + getCurRecording().pause(); +} + +void PeriodicRecording::handleReset() +{ + if (mAutoResize) + { + mRecordingPeriods.clear(); + mRecordingPeriods.push_back(Recording()); + } + else + { + for (std::vector<Recording>::iterator it = mRecordingPeriods.begin(), end_it = mRecordingPeriods.end(); + it != end_it; + ++it) + { + it->reset(); + } + } + mCurPeriod = 0; + getCurRecording().setPlayState(getPlayState()); +} + +void PeriodicRecording::handleSplitTo(PeriodicRecording& other) +{ + getCurRecording().splitTo(other.getCurRecording()); +} + + +F64 PeriodicRecording::getPeriodMean( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + F64 mean = 0; + if (num_periods <= 0) { return mean; } + + S32 total_sample_count = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + S32 period_sample_count = mRecordingPeriods[index].getSampleCount(stat); + mean += mRecordingPeriods[index].getMean(stat) * period_sample_count; + total_sample_count += period_sample_count; + } + } + + if (total_sample_count) + { + mean = mean / total_sample_count; + } + return mean; +} + +F64 PeriodicRecording::getPeriodMin( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + F64 min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat)); + } + return min_val; +} + +F64 PeriodicRecording::getPeriodMax( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat)); + } + return max_val; +} + +F64 PeriodicRecording::getPeriodMin( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + F64 min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat)); + } + return min_val; +} + +F64 PeriodicRecording::getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat)); + } + return max_val; +} + + +F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, total_periods); + + LLUnit<LLUnits::Seconds, F64> total_duration = 0.f; + + F64 mean = 0; + if (num_periods <= 0) { return mean; } + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + LLUnit<LLUnits::Seconds, F64> recording_duration = mRecordingPeriods[index].getDuration(); + mean += mRecordingPeriods[index].getMean(stat) * recording_duration.value(); + total_duration += recording_duration; + } + } + + if (total_duration.value()) + { + mean = mean / total_duration; + } + return mean; +} + + + +/////////////////////////////////////////////////////////////////////// +// ExtendableRecording +/////////////////////////////////////////////////////////////////////// + +void ExtendableRecording::extend() +{ + // stop recording to get latest data + mPotentialRecording.stop(); + // push the data back to accepted recording + mAcceptedRecording.appendRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); + // go back to play state we were in initially + mPotentialRecording.setPlayState(getPlayState()); +} + +void ExtendableRecording::handleStart() +{ + mPotentialRecording.start(); +} + +void ExtendableRecording::handleStop() +{ + mPotentialRecording.pause(); +} + +void ExtendableRecording::handleReset() +{ + mAcceptedRecording.reset(); + mPotentialRecording.reset(); +} + +void ExtendableRecording::handleSplitTo(ExtendableRecording& other) +{ + mPotentialRecording.splitTo(other.mPotentialRecording); +} + + +/////////////////////////////////////////////////////////////////////// +// ExtendablePeriodicRecording +/////////////////////////////////////////////////////////////////////// + + +ExtendablePeriodicRecording::ExtendablePeriodicRecording() +: mAcceptedRecording(0), + mPotentialRecording(0) +{} + +void ExtendablePeriodicRecording::extend() +{ + llassert(mPotentialRecording.getPlayState() == getPlayState()); + // stop recording to get latest data + mPotentialRecording.pause(); + // push the data back to accepted recording + mAcceptedRecording.appendPeriodicRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); + // go back to play state we were in initially + mPotentialRecording.setPlayState(getPlayState()); +} + + +void ExtendablePeriodicRecording::handleStart() +{ + mPotentialRecording.start(); +} + +void ExtendablePeriodicRecording::handleStop() +{ + mPotentialRecording.pause(); +} + +void ExtendablePeriodicRecording::handleReset() +{ + mAcceptedRecording.reset(); + mPotentialRecording.reset(); +} + +void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other) +{ + mPotentialRecording.splitTo(other.mPotentialRecording); +} + + +PeriodicRecording& get_frame_recording() +{ + static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(1000, PeriodicRecording::STARTED)); + return *sRecording; +} + +} + +void LLStopWatchControlsMixinCommon::start() +{ + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + break; + case PAUSED: + handleStart(); + break; + case STARTED: + handleReset(); + break; + default: + llassert(false); + break; + } + mPlayState = STARTED; +} + +void LLStopWatchControlsMixinCommon::stop() +{ + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + break; + case STARTED: + handleStop(); + break; + default: + llassert(false); + break; + } + mPlayState = STOPPED; +} + +void LLStopWatchControlsMixinCommon::pause() +{ + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + break; + case STARTED: + handleStop(); + break; + default: + llassert(false); + break; + } + mPlayState = PAUSED; +} + +void LLStopWatchControlsMixinCommon::resume() +{ + switch (mPlayState) + { + case STOPPED: + handleStart(); + break; + case PAUSED: + handleStart(); + break; + case STARTED: + break; + default: + llassert(false); + break; + } + mPlayState = STARTED; +} + +void LLStopWatchControlsMixinCommon::restart() +{ + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + break; + case PAUSED: + handleReset(); + handleStart(); + break; + case STARTED: + handleReset(); + break; + default: + llassert(false); + break; + } + mPlayState = STARTED; +} + +void LLStopWatchControlsMixinCommon::reset() +{ + handleReset(); +} + +void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state ) +{ + switch(state) + { + case STOPPED: + stop(); + break; + case PAUSED: + pause(); + break; + case STARTED: + start(); + break; + default: + llassert(false); + break; + } + + mPlayState = state; +} |