SH-3499 WIP Ensure asset stats output is correct

fixed trace data gathering and routing from background thread
simplified slave->master thread communication (eliminated redundant recording and proxy object)
improved performance of fast timer data gathering (slow iterators)
master
Richard Linden 2012-11-07 00:38:21 -08:00
parent 0007114cf5
commit 860ff2f7e2
11 changed files with 223 additions and 135 deletions

View File

@ -334,14 +334,13 @@ public:
{}
explicit LLThreadLocalPointer(T* value)
: LLThreadLocalPointerBase(&cleanup)
{
set(value);
}
LLThreadLocalPointer(const LLThreadLocalPointer<T>& other)
: LLThreadLocalPointerBase(other, &cleanup)
: LLThreadLocalPointerBase(other)
{
set(other.get());
}

View File

@ -319,7 +319,7 @@ void LLFastTimer::NamedTimer::buildHierarchy()
// set up initial tree
{
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
{
NamedTimer& timer = *it;
if (&timer == NamedTimerFactory::instance().getRootTimer()) continue;
@ -449,7 +449,7 @@ void LLFastTimer::NamedTimer::resetFrame()
LLSD sd;
{
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
{
NamedTimer& timer = *it;
FrameState& info = timer.getFrameState();
@ -472,7 +472,7 @@ void LLFastTimer::NamedTimer::resetFrame()
}
// reset for next frame
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
{
NamedTimer& timer = *it;
@ -512,7 +512,7 @@ void LLFastTimer::NamedTimer::reset()
// reset all history
{
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
for (instance_iter it = beginInstances(), end_it = endInstances(); it != end_it; ++it)
{
NamedTimer& timer = *it;
if (&timer != NamedTimerFactory::instance().getRootTimer())

View File

@ -112,8 +112,6 @@ void LLQueuedThread::shutdown()
// virtual
S32 LLQueuedThread::update(F32 max_time_ms)
{
LLTrace::get_thread_recorder()->pushToMaster();
if (!mStarted)
{
if (!mThreaded)
@ -511,6 +509,9 @@ void LLQueuedThread::run()
threadedUpdate();
int res = processNextRequest();
LLTrace::get_thread_recorder()->pushToMaster();
if (res == 0)
{
mIdleThread = TRUE;

View File

@ -220,8 +220,7 @@ namespace LLTrace
return AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage()[mAccumulatorIndex];
}
ACCUMULATOR& getAccumulator(AccumulatorBuffer<ACCUMULATOR>* buffer) { return (*buffer)[mAccumulatorIndex]; }
const ACCUMULATOR& getAccumulator(const AccumulatorBuffer<ACCUMULATOR>* buffer) const { return (*buffer)[mAccumulatorIndex]; }
size_t getIndex() const { return mAccumulatorIndex; }
protected:
std::string mName;
@ -396,6 +395,8 @@ namespace LLTrace
T getSum() const { return (T)mSum; }
U32 getSampleCount() const { return mNumSamples; }
private:
T mSum;

View File

@ -117,29 +117,29 @@ void Recording::appendRecording( const Recording& other )
F64 Recording::getSum( const TraceType<CountAccumulator<F64> >& stat ) const
{
return stat.getAccumulator(mCountsFloat).getSum();
return (*mCountsFloat)[stat.getIndex()].getSum();
}
S64 Recording::getSum( const TraceType<CountAccumulator<S64> >& stat ) const
{
return stat.getAccumulator(mCounts).getSum();
return (*mCounts)[stat.getIndex()].getSum();
}
F64 Recording::getSum( const TraceType<MeasurementAccumulator<F64> >& stat ) const
{
return (F64)stat.getAccumulator(mMeasurementsFloat).getSum();
return (F64)(*mMeasurementsFloat)[stat.getIndex()].getSum();
}
S64 Recording::getSum( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
return (S64)stat.getAccumulator(mMeasurements).getSum();
return (S64)(*mMeasurements)[stat.getIndex()].getSum();
}
F64 Recording::getPerSec( const TraceType<CountAccumulator<F64> >& stat ) const
{
F64 sum = stat.getAccumulator(mCountsFloat).getSum();
F64 sum = (*mCountsFloat)[stat.getIndex()].getSum();
return (sum != 0.0)
? (sum / mElapsedSeconds)
: 0.0;
@ -147,15 +147,26 @@ F64 Recording::getPerSec( const TraceType<CountAccumulator<F64> >& stat ) const
F64 Recording::getPerSec( const TraceType<CountAccumulator<S64> >& stat ) const
{
S64 sum = stat.getAccumulator(mCounts).getSum();
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 = stat.getAccumulator(mMeasurementsFloat).getSum();
F64 sum = (*mMeasurementsFloat)[stat.getIndex()].getSum();
return (sum != 0.0)
? (sum / mElapsedSeconds)
: 0.0;
@ -163,7 +174,7 @@ F64 Recording::getPerSec( const TraceType<MeasurementAccumulator<F64> >& stat )
F64 Recording::getPerSec( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
S64 sum = stat.getAccumulator(mMeasurements).getSum();
S64 sum = (*mMeasurements)[stat.getIndex()].getSum();
return (sum != 0)
? ((F64)sum / mElapsedSeconds)
: 0.0;
@ -171,62 +182,62 @@ F64 Recording::getPerSec( const TraceType<MeasurementAccumulator<S64> >& stat )
F64 Recording::getMin( const TraceType<MeasurementAccumulator<F64> >& stat ) const
{
return stat.getAccumulator(mMeasurementsFloat).getMin();
return (*mMeasurementsFloat)[stat.getIndex()].getMin();
}
S64 Recording::getMin( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
return stat.getAccumulator(mMeasurements).getMin();
return (*mMeasurements)[stat.getIndex()].getMin();
}
F64 Recording::getMax( const TraceType<MeasurementAccumulator<F64> >& stat ) const
{
return stat.getAccumulator(mMeasurementsFloat).getMax();
return (*mMeasurementsFloat)[stat.getIndex()].getMax();
}
S64 Recording::getMax( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
return stat.getAccumulator(mMeasurements).getMax();
return (*mMeasurements)[stat.getIndex()].getMax();
}
F64 Recording::getMean( const TraceType<MeasurementAccumulator<F64> >& stat ) const
{
return stat.getAccumulator(mMeasurementsFloat).getMean();
return (*mMeasurementsFloat)[stat.getIndex()].getMean();
}
F64 Recording::getMean( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
return stat.getAccumulator(mMeasurements).getMean();
return (*mMeasurements)[stat.getIndex()].getMean();
}
F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<F64> >& stat ) const
{
return stat.getAccumulator(mMeasurementsFloat).getStandardDeviation();
return (*mMeasurementsFloat)[stat.getIndex()].getStandardDeviation();
}
F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
return stat.getAccumulator(mMeasurements).getStandardDeviation();
return (*mMeasurements)[stat.getIndex()].getStandardDeviation();
}
F64 Recording::getLastValue( const TraceType<MeasurementAccumulator<F64> >& stat ) const
{
return stat.getAccumulator(mMeasurementsFloat).getLastValue();
return (*mMeasurementsFloat)[stat.getIndex()].getLastValue();
}
S64 Recording::getLastValue( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
return stat.getAccumulator(mMeasurements).getLastValue();
return (*mMeasurements)[stat.getIndex()].getLastValue();
}
U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<F64> >& stat ) const
{
return stat.getAccumulator(mMeasurementsFloat).getSampleCount();
return (*mMeasurementsFloat)[stat.getIndex()].getSampleCount();
}
U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<S64> >& stat ) const
{
return stat.getAccumulator(mMeasurements).getSampleCount();
return (*mMeasurements)[stat.getIndex()].getSampleCount();
}
@ -235,13 +246,14 @@ U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<S64> >& st
// PeriodicRecording
///////////////////////////////////////////////////////////////////////
PeriodicRecording::PeriodicRecording( S32 num_periods )
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()
@ -252,7 +264,7 @@ PeriodicRecording::~PeriodicRecording()
void PeriodicRecording::nextPeriod()
{
EPlayState play_state = getPlayState();
EStopWatchState play_state = getPlayState();
Recording& old_recording = getCurRecordingPeriod();
mCurPeriod = (mCurPeriod + 1) % mNumPeriods;
old_recording.splitTo(getCurRecordingPeriod());
@ -286,24 +298,44 @@ Recording& PeriodicRecording::getTotalRecording()
return mTotalRecording;
}
void PeriodicRecording::handleStart()
void PeriodicRecording::start()
{
getCurRecordingPeriod().handleStart();
getCurRecordingPeriod().start();
}
void PeriodicRecording::handleStop()
void PeriodicRecording::stop()
{
getCurRecordingPeriod().handleStop();
getCurRecordingPeriod().stop();
}
void PeriodicRecording::handleReset()
void PeriodicRecording::pause()
{
getCurRecordingPeriod().handleReset();
getCurRecordingPeriod().pause();
}
void PeriodicRecording::handleSplitTo( PeriodicRecording& other )
void PeriodicRecording::resume()
{
getCurRecordingPeriod().handleSplitTo(other.getCurRecordingPeriod());
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());
}
@ -317,38 +349,59 @@ void ExtendableRecording::extend()
mPotentialRecording.reset();
}
void ExtendableRecording::handleStart()
void ExtendableRecording::start()
{
mPotentialRecording.handleStart();
mPotentialRecording.start();
}
void ExtendableRecording::handleStop()
void ExtendableRecording::stop()
{
mPotentialRecording.handleStop();
mPotentialRecording.stop();
}
void ExtendableRecording::handleReset()
void ExtendableRecording::pause()
{
mAcceptedRecording.handleReset();
mPotentialRecording.handleReset();
mPotentialRecording.pause();
}
void ExtendableRecording::handleSplitTo( ExtendableRecording& other )
void ExtendableRecording::resume()
{
mPotentialRecording.handleSplitTo(other.mPotentialRecording);
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 PeriodicRecording sRecording(64);
return sRecording;
static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(64, PeriodicRecording::STARTED));
return *sRecording;
}
}
void LLStopWatchControlsMixinCommon::start()
{
switch (mPlayState)
switch (mState)
{
case STOPPED:
handleReset();
@ -360,13 +413,16 @@ void LLStopWatchControlsMixinCommon::start()
case STARTED:
handleReset();
break;
default:
llassert(false);
break;
}
mPlayState = STARTED;
mState = STARTED;
}
void LLStopWatchControlsMixinCommon::stop()
{
switch (mPlayState)
switch (mState)
{
case STOPPED:
break;
@ -376,13 +432,16 @@ void LLStopWatchControlsMixinCommon::stop()
case STARTED:
handleStop();
break;
default:
llassert(false);
break;
}
mPlayState = STOPPED;
mState = STOPPED;
}
void LLStopWatchControlsMixinCommon::pause()
{
switch (mPlayState)
switch (mState)
{
case STOPPED:
break;
@ -391,13 +450,16 @@ void LLStopWatchControlsMixinCommon::pause()
case STARTED:
handleStop();
break;
default:
llassert(false);
break;
}
mPlayState = PAUSED;
mState = PAUSED;
}
void LLStopWatchControlsMixinCommon::resume()
{
switch (mPlayState)
switch (mState)
{
case STOPPED:
handleStart();
@ -407,13 +469,16 @@ void LLStopWatchControlsMixinCommon::resume()
break;
case STARTED:
break;
default:
llassert(false);
break;
}
mPlayState = STARTED;
mState = STARTED;
}
void LLStopWatchControlsMixinCommon::restart()
{
switch (mPlayState)
switch (mState)
{
case STOPPED:
handleReset();
@ -426,11 +491,33 @@ void LLStopWatchControlsMixinCommon::restart()
case STARTED:
handleReset();
break;
default:
llassert(false);
break;
}
mPlayState = STARTED;
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;
}

View File

@ -39,43 +39,42 @@ class LL_COMMON_API LLStopWatchControlsMixinCommon
public:
virtual ~LLStopWatchControlsMixinCommon() {}
enum EPlayState
enum EStopWatchState
{
STOPPED,
PAUSED,
STARTED
};
void start();
void stop();
void pause();
void resume();
void restart();
void reset();
virtual void start();
virtual void stop();
virtual void pause();
virtual void resume();
virtual void restart();
virtual void reset();
bool isStarted() const { return mPlayState == STARTED; }
bool isPaused() const { return mPlayState == PAUSED; }
bool isStopped() const { return mPlayState == STOPPED; }
EPlayState getPlayState() const { return mPlayState; }
bool isStarted() const { return mState == STARTED; }
bool isPaused() const { return mState == PAUSED; }
bool isStopped() const { return mState == STOPPED; }
EStopWatchState getPlayState() const { return mState; }
protected:
LLStopWatchControlsMixinCommon()
: mPlayState(STOPPED)
: mState(STOPPED)
{}
// derived classes can call this from their constructor in order
// to enforce invariants
void forceState(EPlayState state) { mPlayState = state; }
// derived classes can call this from their copy constructor in order
// to duplicate play state of source
void initTo(EStopWatchState state);
private:
// trigger data accumulation (without reset)
virtual void handleStart() = 0;
// stop data accumulation, should put object in queryable state
virtual void handleStop() = 0;
// clear accumulated values, can be called while started
virtual void handleReset() = 0;
// trigger active behavior (without reset)
virtual void handleStart(){};
// stop active behavior
virtual void handleStop(){};
// clear accumulated state, can be called while started
virtual void handleReset(){};
EPlayState mPlayState;
EStopWatchState mState;
};
template<typename DERIVED>
@ -83,19 +82,20 @@ class LLStopWatchControlsMixin
: public LLStopWatchControlsMixinCommon
{
public:
void splitTo(DERIVED& other)
typedef LLStopWatchControlsMixin<DERIVED> self_t;
virtual void splitTo(DERIVED& other)
{
handleSplitTo(other);
}
void splitFrom(DERIVED& other)
virtual void splitFrom(DERIVED& other)
{
other.handleSplitTo(*this);
static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this));
}
private:
// atomically stop this object while starting the other
// no data can be missed in between stop and start
virtual void handleSplitTo(DERIVED& other) = 0;
virtual void handleSplitTo(DERIVED& other) {};
};
@ -108,20 +108,20 @@ namespace LLTrace
Recording(const Recording& other)
{
mSamplingTimer = other.mSamplingTimer;
mElapsedSeconds = other.mElapsedSeconds;
mCountsFloat = other.mCountsFloat;
mSamplingTimer = other.mSamplingTimer;
mElapsedSeconds = other.mElapsedSeconds;
mCountsFloat = other.mCountsFloat;
mMeasurementsFloat = other.mMeasurementsFloat;
mCounts = other.mCounts;
mMeasurements = other.mMeasurements;
mStackTimers = other.mStackTimers;
mCounts = other.mCounts;
mMeasurements = other.mMeasurements;
mStackTimers = other.mStackTimers;
LLStopWatchControlsMixin::initTo(other.getPlayState());
if (other.isStarted())
{
handleStart();
}
forceState(other.getPlayState());
}
~Recording();
@ -149,6 +149,10 @@ namespace LLTrace
return (T)getPerSec(static_cast<const TraceType<CountAccumulator<StorageType<T>::type_t> >&> (stat));
}
U32 getSampleCount(const TraceType<CountAccumulator<F64> >& stat) const;
U32 getSampleCount(const TraceType<CountAccumulator<S64> >& stat) const;
// Measurement accessors
F64 getSum(const TraceType<MeasurementAccumulator<F64> >& stat) const;
S64 getSum(const TraceType<MeasurementAccumulator<S64> >& stat) const;
@ -211,14 +215,15 @@ namespace LLTrace
LLUnit::Seconds<F64> getDuration() const { return mElapsedSeconds; }
private:
friend class ThreadRecorder;
// implementation for LLStopWatchControlsMixin
/*virtual*/ void handleStart();
/*virtual*/ void handleStop();
/*virtual*/ void handleReset();
/*virtual*/ void handleSplitTo(Recording& other);
private:
friend class ThreadRecorder;
// returns data for current thread
class ThreadRecorder* getThreadRecorder();
@ -236,7 +241,7 @@ namespace LLTrace
: public LLStopWatchControlsMixin<PeriodicRecording>
{
public:
PeriodicRecording(S32 num_periods);
PeriodicRecording(S32 num_periods, EStopWatchState state = STOPPED);
~PeriodicRecording();
void nextPeriod();
@ -359,15 +364,17 @@ namespace LLTrace
return mean;
}
private:
// implementation for LLStopWatchControlsMixin
/*virtual*/ void handleStart();
/*virtual*/ void handleStop();
/*virtual*/ void handleReset();
/*virtual*/ void handleSplitTo(PeriodicRecording& other);
/*virtual*/ void start();
/*virtual*/ void stop();
/*virtual*/ void pause();
/*virtual*/ void resume();
/*virtual*/ void restart();
/*virtual*/ void reset();
/*virtual*/ void splitTo(PeriodicRecording& other);
/*virtual*/ void splitFrom(PeriodicRecording& other);
private:
Recording* mRecordingPeriods;
Recording mTotalRecording;
bool mTotalValid;
@ -382,13 +389,16 @@ namespace LLTrace
{
void extend();
private:
// implementation for LLStopWatchControlsMixin
/*virtual*/ void handleStart();
/*virtual*/ void handleStop();
/*virtual*/ void handleReset();
/*virtual*/ void handleSplitTo(ExtendableRecording& other);
/*virtual*/ void start();
/*virtual*/ void stop();
/*virtual*/ void pause();
/*virtual*/ void resume();
/*virtual*/ void restart();
/*virtual*/ void reset();
/*virtual*/ void splitTo(ExtendableRecording& other);
/*virtual*/ void splitFrom(ExtendableRecording& other);
private:
Recording mAcceptedRecording;
Recording mPotentialRecording;
};

View File

@ -171,15 +171,20 @@ void SlaveThreadRecorder::SharedData::copyTo( Recording& sink )
// MasterThreadRecorder
///////////////////////////////////////////////////////////////////////
LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data");
void MasterThreadRecorder::pullFromSlaveThreads()
{
LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
if (mActiveRecordings.empty()) return;
LLMutexLock lock(&mSlaveListMutex);
Recording& target_recording = mActiveRecordings.front().mBaseline;
for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
it != end_it;
++it)
{
(*it)->mRecorder->mSharedData.copyTo((*it)->mSlaveRecording);
(*it)->mSharedData.copyTo(target_recording);
}
}
@ -187,7 +192,7 @@ void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child )
{
LLMutexLock lock(&mSlaveListMutex);
mSlaveThreadRecorders.push_back(new SlaveThreadRecorderProxy(child));
mSlaveThreadRecorders.push_back(child);
}
void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child )
@ -198,7 +203,7 @@ void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child )
it != end_it;
++it)
{
if ((*it)->mRecorder == child)
if ((*it) == child)
{
mSlaveThreadRecorders.erase(it);
break;
@ -212,12 +217,4 @@ void MasterThreadRecorder::pushToMaster()
MasterThreadRecorder::MasterThreadRecorder()
{}
///////////////////////////////////////////////////////////////////////
// MasterThreadRecorder::SlaveThreadTraceProxy
///////////////////////////////////////////////////////////////////////
MasterThreadRecorder::SlaveThreadRecorderProxy::SlaveThreadRecorderProxy( class SlaveThreadRecorder* recorder)
: mRecorder(recorder)
{}
}

View File

@ -81,17 +81,8 @@ namespace LLTrace
LLMutex* getSlaveListMutex() { return &mSlaveListMutex; }
private:
struct SlaveThreadRecorderProxy
{
SlaveThreadRecorderProxy(class SlaveThreadRecorder* recorder);
class SlaveThreadRecorder* mRecorder;
Recording mSlaveRecording;
private:
//no need to copy these and then have to duplicate the storage
SlaveThreadRecorderProxy(const SlaveThreadRecorderProxy& other) {}
};
typedef std::list<SlaveThreadRecorderProxy*> slave_thread_recorder_list_t;
typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t;
slave_thread_recorder_list_t mSlaveThreadRecorders;
LLMutex mSlaveListMutex;

View File

@ -494,7 +494,7 @@ void record_response(LLViewerAssetType::EType at, bool with_http, bool is_temp,
{
const EViewerAssetCategories eac(asset_type_to_category(at, with_http, is_temp));
sResponse[int(eac)].sample<LLTrace::Seconds>(duration);
sResponse[int(eac)].sample<LLTrace::Microseconds>(duration);
}
void record_avatar_stats()

View File

@ -349,7 +349,10 @@ void update_statistics()
}
LLStatViewer::FPS.add(1);
LLStatViewer::FPS_SAMPLE.sample(LLTrace::get_frame_recording().getTotalRecording().getPerSec(LLStatViewer::FPS));
if (LLTrace::get_frame_recording().getTotalRecording().getSampleCount(LLStatViewer::FPS))
{
LLStatViewer::FPS_SAMPLE.sample(LLTrace::get_frame_recording().getTotalRecording().getPerSec(LLStatViewer::FPS));
}
F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
LLStatViewer::LAYERS_KBIT.add<LLTrace::Bits>(layer_bits);
LLStatViewer::OBJECT_KBIT.add(gObjectData);

View File

@ -266,7 +266,6 @@ namespace tut
ensure("Global gViewerAssetStats should still be NULL", (NULL == gViewerAssetStats));
LLSD sd_full = it->asLLSD(false);
llinfos << ll_pretty_print_sd(sd_full) << llendl;
// Default (NULL) region ID doesn't produce LLSD results so should
// get an empty map back from output