SH-3275 WIP Run viewer metrics for object update messages

factored out lltrace::sampler into separate file
added rudimentary lltrace support to llstatgraph
made llstatgraph use param blocks more effectively
moves initial set of stats over to lltrace
removed windows.h #defines for min and max
master
Richard Linden 2012-09-30 10:41:29 -07:00
parent 38354e1906
commit b1baf982b1
16 changed files with 555 additions and 290 deletions

View File

@ -101,6 +101,7 @@ set(llcommon_SOURCE_FILES
llthreadsafequeue.cpp
lltimer.cpp
lltrace.cpp
lltracesampler.cpp
lluri.cpp
lluuid.cpp
llworkerthread.cpp
@ -243,6 +244,7 @@ set(llcommon_HEADER_FILES
llthreadsafequeue.h
lltimer.h
lltrace.h
lltracesampler.h
lltreeiterators.h
lltypeinfolookup.h
lluri.h

View File

@ -39,6 +39,8 @@
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#undef min
#undef max
#endif
#include <boost/noncopyable.hpp>

View File

@ -26,6 +26,7 @@
#include "linden_common.h"
#include "lltrace.h"
#include "lltracesampler.h"
#include "llthread.h"
namespace LLTrace
@ -55,77 +56,6 @@ MasterThreadTrace& getMasterThreadTrace()
return *gMasterThreadTrace;
}
///////////////////////////////////////////////////////////////////////
// Sampler
///////////////////////////////////////////////////////////////////////
Sampler::Sampler(ThreadTrace* thread_trace)
: mElapsedSeconds(0),
mIsStarted(false),
mThreadTrace(thread_trace)
{
}
Sampler::~Sampler()
{
}
void Sampler::start()
{
reset();
resume();
}
void Sampler::reset()
{
mF32Stats.reset();
mS32Stats.reset();
mStackTimers.reset();
mElapsedSeconds = 0.0;
mSamplingTimer.reset();
}
void Sampler::resume()
{
if (!mIsStarted)
{
mSamplingTimer.reset();
getThreadTrace()->activate(this);
mIsStarted = true;
}
}
void Sampler::stop()
{
if (mIsStarted)
{
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
getThreadTrace()->deactivate(this);
mIsStarted = false;
}
}
ThreadTrace* Sampler::getThreadTrace()
{
return mThreadTrace;
}
void Sampler::makePrimary()
{
mF32Stats.makePrimary();
mS32Stats.makePrimary();
mStackTimers.makePrimary();
}
void Sampler::mergeFrom( const Sampler* other )
{
mF32Stats.mergeFrom(other->mF32Stats);
mS32Stats.mergeFrom(other->mS32Stats);
mStackTimers.mergeFrom(other->mStackTimers);
}
///////////////////////////////////////////////////////////////////////
// MasterThreadTrace
///////////////////////////////////////////////////////////////////////
@ -148,6 +78,11 @@ ThreadTrace::~ThreadTrace()
delete mPrimarySampler;
}
Sampler* ThreadTrace::getPrimarySampler()
{
return mPrimarySampler;
}
void ThreadTrace::activate( Sampler* sampler )
{
flushPrimary();
@ -205,6 +140,34 @@ void SlaveThreadTrace::pushToMaster()
mSharedData.copyFrom(mPrimarySampler);
}
void SlaveThreadTrace::SharedData::copyFrom( Sampler* source )
{
LLMutexLock lock(&mSamplerMutex);
{
mSampler->mergeFrom(source);
}
}
void SlaveThreadTrace::SharedData::copyTo( Sampler* sink )
{
LLMutexLock lock(&mSamplerMutex);
{
sink->mergeFrom(mSampler);
}
}
SlaveThreadTrace::SharedData::~SharedData()
{
delete mSampler;
}
SlaveThreadTrace::SharedData::SharedData( Sampler* sampler ) : mSampler(sampler)
{}
///////////////////////////////////////////////////////////////////////
// MasterThreadTrace
///////////////////////////////////////////////////////////////////////
@ -217,7 +180,7 @@ void MasterThreadTrace::pullFromSlaveThreads()
it != end_it;
++it)
{
it->mSlaveTrace->mSharedData.copyTo(it->mSamplerStorage);
(*it)->mSlaveTrace->mSharedData.copyTo((*it)->mSamplerStorage);
}
}
@ -225,7 +188,7 @@ void MasterThreadTrace::addSlaveThread( class SlaveThreadTrace* child )
{
LLMutexLock lock(&mSlaveListMutex);
mSlaveThreadTraces.push_back(SlaveThreadTraceProxy(child, createSampler()));
mSlaveThreadTraces.push_back(new SlaveThreadTraceProxy(child, createSampler()));
}
void MasterThreadTrace::removeSlaveThread( class SlaveThreadTrace* child )
@ -236,7 +199,7 @@ void MasterThreadTrace::removeSlaveThread( class SlaveThreadTrace* child )
it != end_it;
++it)
{
if (it->mSlaveTrace == child)
if ((*it)->mSlaveTrace == child)
{
mSlaveThreadTraces.erase(it);
break;
@ -266,5 +229,4 @@ MasterThreadTrace::SlaveThreadTraceProxy::~SlaveThreadTraceProxy()
delete mSamplerStorage;
}
}

View File

@ -43,14 +43,16 @@
namespace LLTrace
{
class Sampler;
void init();
void cleanup();
class MasterThreadTrace& getMasterThreadTrace();
class LL_COMMON_API MasterThreadTrace& getMasterThreadTrace();
// one per thread per type
template<typename ACCUMULATOR>
class AccumulatorBuffer
class LL_COMMON_API AccumulatorBuffer
{
static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
private:
@ -64,6 +66,8 @@ namespace LLTrace
public:
// copying an accumulator buffer does not copy the actual contents, but simply initializes the buffer size
// to be identical to the other buffer
AccumulatorBuffer(const AccumulatorBuffer& other = getDefaultBuffer())
: mStorageSize(other.mStorageSize),
mStorage(new ACCUMULATOR[other.mStorageSize]),
@ -150,28 +154,30 @@ namespace LLTrace
template<typename ACCUMULATOR> LLThreadLocalPtr<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage;
template<typename ACCUMULATOR>
class Trace
class LL_COMMON_API TraceType
{
public:
Trace(const std::string& name)
TraceType(const std::string& name)
: mName(name)
{
mAccumulatorIndex = AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer().reserveSlot();
}
LL_FORCE_INLINE ACCUMULATOR& getAccumulator()
LL_FORCE_INLINE ACCUMULATOR& getPrimaryAccumulator()
{
return AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage()[mAccumulatorIndex];
}
private:
ACCUMULATOR& getAccumulator(AccumulatorBuffer<ACCUMULATOR>& buffer) { return buffer[mAccumulatorIndex]; }
protected:
std::string mName;
size_t mAccumulatorIndex;
};
template<typename T>
class StatAccumulator
class LL_COMMON_API StatAccumulator
{
public:
StatAccumulator()
@ -217,6 +223,11 @@ namespace LLTrace
mMax = 0;
}
T getSum() { return mSum; }
T getMin() { return mMin; }
T getMax() { return mMax; }
T getMean() { return mSum / (T)mNumSamples; }
private:
T mSum,
mMin,
@ -226,20 +237,23 @@ namespace LLTrace
};
template <typename T>
class Stat : public Trace<StatAccumulator<T> >
class LL_COMMON_API Stat
: public TraceType<StatAccumulator<T> >,
public LLInstanceTracker<Stat<T>, std::string>
{
public:
Stat(const std::string& name)
: Trace(name)
: TraceType(name),
LLInstanceTracker(name)
{}
void sample(T value)
{
getAccumulator().sample(value);
getPrimaryAccumulator().sample(value);
}
};
struct TimerAccumulator
struct LL_COMMON_API TimerAccumulator
{
U32 mTotalTimeCounter,
mChildTimeCounter,
@ -267,11 +281,11 @@ namespace LLTrace
};
class BlockTimer : public Trace<TimerAccumulator>
class LL_COMMON_API BlockTimer : public TraceType<TimerAccumulator>
{
public:
BlockTimer(const char* name)
: Trace(name)
: TraceType(name)
{}
struct Recorder
@ -287,7 +301,7 @@ namespace LLTrace
: mLastRecorder(sCurRecorder)
{
mStartTime = getCPUClockCount32();
TimerAccumulator* accumulator = &block_timer.getAccumulator(); // get per-thread accumulator
TimerAccumulator* accumulator = &block_timer.getPrimaryAccumulator(); // get per-thread accumulator
accumulator->mActiveCount++;
accumulator->mCalls++;
accumulator->mMoveUpTree |= (accumulator->mParent->mActiveCount == 0);
@ -353,44 +367,7 @@ namespace LLTrace
static Recorder::StackEntry sCurRecorder;
};
class Sampler
{
public:
~Sampler();
void makePrimary();
void start();
void stop();
void resume();
void mergeFrom(const Sampler* other);
void reset();
bool isStarted() { return mIsStarted; }
private:
friend class ThreadTrace;
Sampler(class ThreadTrace* thread_trace);
// no copy
Sampler(const Sampler& other) {}
// returns data for current thread
class ThreadTrace* getThreadTrace();
AccumulatorBuffer<StatAccumulator<F32> > mF32Stats;
AccumulatorBuffer<StatAccumulator<S32> > mS32Stats;
AccumulatorBuffer<TimerAccumulator> mStackTimers;
bool mIsStarted;
LLTimer mSamplingTimer;
F64 mElapsedSeconds;
ThreadTrace* mThreadTrace;
};
class ThreadTrace
class LL_COMMON_API ThreadTrace
{
public:
ThreadTrace();
@ -406,13 +383,13 @@ namespace LLTrace
virtual void pushToMaster() = 0;
Sampler* getPrimarySampler() { return mPrimarySampler; }
Sampler* getPrimarySampler();
protected:
Sampler* mPrimarySampler;
std::list<Sampler*> mActiveSamplers;
};
class MasterThreadTrace : public ThreadTrace
class LL_COMMON_API MasterThreadTrace : public ThreadTrace
{
public:
MasterThreadTrace();
@ -433,14 +410,17 @@ namespace LLTrace
~SlaveThreadTraceProxy();
class SlaveThreadTrace* mSlaveTrace;
Sampler* mSamplerStorage;
private:
//no need to copy these and then have to duplicate the storage
SlaveThreadTraceProxy(const SlaveThreadTraceProxy& other) {}
};
typedef std::list<SlaveThreadTraceProxy> slave_thread_trace_list_t;
typedef std::list<SlaveThreadTraceProxy*> slave_thread_trace_list_t;
slave_thread_trace_list_t mSlaveThreadTraces;
LLMutex mSlaveListMutex;
};
class SlaveThreadTrace : public ThreadTrace
class LL_COMMON_API SlaveThreadTrace : public ThreadTrace
{
public:
SlaveThreadTrace();
@ -457,31 +437,12 @@ namespace LLTrace
{
public:
explicit
SharedData(Sampler* sampler)
: mSampler(sampler)
{
}
SharedData(Sampler* sampler);
~SharedData()
{
delete mSampler;
}
~SharedData();
void copyFrom(Sampler* source)
{
LLMutexLock lock(&mSamplerMutex);
{
mSampler->mergeFrom(source);
}
}
void copyTo(Sampler* sink)
{
LLMutexLock lock(&mSamplerMutex);
{
sink->mergeFrom(mSampler);
}
}
void copyFrom(Sampler* source);
void copyTo(Sampler* sink);
private:
// add a cache line's worth of unused space to avoid any potential of false sharing
LLMutex mSamplerMutex;
@ -489,14 +450,6 @@ namespace LLTrace
};
SharedData mSharedData;
};
class TimeInterval
{
public:
void start() {}
void stop() {}
void resume() {}
};
}
#endif // LL_LLTRACE_H

View File

@ -0,0 +1,103 @@
/**
* @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 "lltracesampler.h"
namespace LLTrace
{
///////////////////////////////////////////////////////////////////////
// Sampler
///////////////////////////////////////////////////////////////////////
Sampler::Sampler(ThreadTrace* thread_trace)
: mElapsedSeconds(0),
mIsStarted(false),
mThreadTrace(thread_trace)
{
}
Sampler::~Sampler()
{
}
void Sampler::start()
{
reset();
resume();
}
void Sampler::reset()
{
mF32Stats.reset();
mS32Stats.reset();
mStackTimers.reset();
mElapsedSeconds = 0.0;
mSamplingTimer.reset();
}
void Sampler::resume()
{
if (!mIsStarted)
{
mSamplingTimer.reset();
getThreadTrace()->activate(this);
mIsStarted = true;
}
}
void Sampler::stop()
{
if (mIsStarted)
{
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
getThreadTrace()->deactivate(this);
mIsStarted = false;
}
}
ThreadTrace* Sampler::getThreadTrace()
{
return mThreadTrace;
}
void Sampler::makePrimary()
{
mF32Stats.makePrimary();
mS32Stats.makePrimary();
mStackTimers.makePrimary();
}
void Sampler::mergeFrom( const Sampler* other )
{
mF32Stats.mergeFrom(other->mF32Stats);
mS32Stats.mergeFrom(other->mS32Stats);
mStackTimers.mergeFrom(other->mStackTimers);
}
}

View File

@ -0,0 +1,91 @@
/**
* @file lltracesampler.h
* @brief Sampling object for collecting runtime statistics originating from lltrace.
*
* $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$
*/
#ifndef LL_LLTRACESAMPLER_H
#define LL_LLTRACESAMPLER_H
#include "stdtypes.h"
#include "llpreprocessor.h"
#include "lltrace.h"
namespace LLTrace
{
class LL_COMMON_API Sampler
{
public:
~Sampler();
void makePrimary();
void start();
void stop();
void resume();
void mergeFrom(const Sampler* other);
void reset();
bool isStarted() { return mIsStarted; }
F32 getSum(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getSum(); }
F32 getMin(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMin(); }
F32 getMax(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMax(); }
F32 getMean(Stat<F32>& stat) { return stat.getAccumulator(mF32Stats).getMean(); }
S32 getSum(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getSum(); }
S32 getMin(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMin(); }
S32 getMax(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMax(); }
S32 getMean(Stat<S32>& stat) { return stat.getAccumulator(mS32Stats).getMean(); }
F64 getSampleTime() { return mElapsedSeconds; }
private:
friend class ThreadTrace;
Sampler(class ThreadTrace* thread_trace);
// no copy
Sampler(const Sampler& other) {}
// returns data for current thread
class ThreadTrace* getThreadTrace();
//TODO: take snapshot at sampler start so we can simplify updates
//AccumulatorBuffer<StatAccumulator<F32> > mF32StatsStart;
//AccumulatorBuffer<StatAccumulator<S32> > mS32StatsStart;
//AccumulatorBuffer<TimerAccumulator> mStackTimersStart;
AccumulatorBuffer<StatAccumulator<F32> > mF32Stats;
AccumulatorBuffer<StatAccumulator<S32> > mS32Stats;
AccumulatorBuffer<TimerAccumulator> mStackTimers;
bool mIsStarted;
LLTimer mSamplingTimer;
F64 mElapsedSeconds;
ThreadTrace* mThreadTrace;
};
}
#endif // LL_LLTRACESAMPLER_H

View File

@ -543,6 +543,8 @@ extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#undef min
#undef max
//----------------------------------------------------------------------------
#include <GL/gl.h>

View File

@ -36,6 +36,7 @@
#include "llstat.h"
#include "lluictrlfactory.h"
#include "lltracesampler.h"
///////////////////////////////////////////////////////////////////////////////////
@ -46,6 +47,8 @@ LLStatBar::LLStatBar(const Params& p)
mMinBar(p.bar_min),
mMaxBar(p.bar_max),
mStatp(LLStat::getInstance(p.stat)),
mFloatStatp(LLTrace::Stat<F32>::getInstance(p.stat)),
mIntStatp(LLTrace::Stat<S32>::getInstance(p.stat)),
mTickSpacing(p.tick_spacing),
mLabelSpacing(p.label_spacing),
mPrecision(p.precision),
@ -84,29 +87,65 @@ BOOL LLStatBar::handleMouseDown(S32 x, S32 y, MASK mask)
void LLStatBar::draw()
{
if (!mStatp)
{
// llinfos << "No stats for statistics bar!" << llendl;
return;
}
F32 current = 0.f,
min = 0.f,
max = 0.f,
mean = 0.f;
// Get the values.
F32 current, min, max, mean;
if (mPerSec)
if (mStatp)
{
current = mStatp->getCurrentPerSec();
min = mStatp->getMinPerSec();
max = mStatp->getMaxPerSec();
mean = mStatp->getMeanPerSec();
// Get the values.
if (mPerSec)
{
current = mStatp->getCurrentPerSec();
min = mStatp->getMinPerSec();
max = mStatp->getMaxPerSec();
mean = mStatp->getMeanPerSec();
}
else
{
current = mStatp->getCurrent();
min = mStatp->getMin();
max = mStatp->getMax();
mean = mStatp->getMean();
}
}
else
else if (mFloatStatp)
{
current = mStatp->getCurrent();
min = mStatp->getMin();
max = mStatp->getMax();
mean = mStatp->getMean();
LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
if (mPerSec)
{
current = sampler->getSum(*mFloatStatp) / sampler->getSampleTime();
min = sampler->getMin(*mFloatStatp) / sampler->getSampleTime();
max = sampler->getMax(*mFloatStatp) / sampler->getSampleTime();
mean = sampler->getMean(*mFloatStatp) / sampler->getSampleTime();
}
else
{
current = sampler->getSum(*mFloatStatp);
min = sampler->getMin(*mFloatStatp);
max = sampler->getMax(*mFloatStatp);
mean = sampler->getMean(*mFloatStatp);
}
}
else if (mIntStatp)
{
LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
if (mPerSec)
{
current = (F32)sampler->getSum(*mIntStatp) / sampler->getSampleTime();
min = (F32)sampler->getMin(*mIntStatp) / sampler->getSampleTime();
max = (F32)sampler->getMax(*mIntStatp) / sampler->getSampleTime();
mean = (F32)sampler->getMean(*mIntStatp) / sampler->getSampleTime();
}
else
{
current = (F32)sampler->getSum(*mIntStatp);
min = (F32)sampler->getMin(*mIntStatp);
max = (F32)sampler->getMax(*mIntStatp);
mean = (F32)sampler->getMean(*mIntStatp);
}
}
if ((mUpdatesPerSec == 0.f) || (mUpdateTimer.getElapsedTimeF32() > 1.f/mUpdatesPerSec) || (mValue == 0.f))
{
@ -153,7 +192,7 @@ void LLStatBar::draw()
LLFontGL::RIGHT, LLFontGL::TOP);
value_format = llformat( "%%.%df", mPrecision);
if (mDisplayBar)
if (mDisplayBar && mStatp)
{
std::string tick_label;
@ -213,9 +252,9 @@ void LLStatBar::draw()
right = (S32) ((max - mMinBar) * value_scale);
gl_rect_2d(left, top, right, bottom, LLColor4(1.f, 0.f, 0.f, 0.25f));
S32 num_values = mStatp->getNumValues() - 1;
if (mDisplayHistory)
{
S32 num_values = mStatp->getNumValues() - 1;
S32 i;
for (i = 0; i < num_values; i++)
{
@ -270,7 +309,7 @@ LLRect LLStatBar::getRequiredRect()
if (mDisplayBar)
{
if (mDisplayHistory)
if (mDisplayHistory && mStatp)
{
rect.mTop = 35 + mStatp->getNumBins();
}

View File

@ -29,6 +29,7 @@
#include "llview.h"
#include "llframetimer.h"
#include "lltrace.h"
class LLStat;
@ -92,6 +93,8 @@ private:
BOOL mDisplayMean; // If true, display mean, if false, display current value
LLStat* mStatp;
LLTrace::Stat<F32>* mFloatStatp;
LLTrace::Stat<S32>* mIntStatp;
LLFrameTimer mUpdateTimer;
LLUIString mLabel;

View File

@ -35,28 +35,38 @@
#include "llstat.h"
#include "llgl.h"
#include "llglheaders.h"
#include "lltracesampler.h"
//#include "llviewercontrol.h"
///////////////////////////////////////////////////////////////////////////////////
LLStatGraph::LLStatGraph(const LLView::Params& p)
: LLView(p)
LLStatGraph::LLStatGraph(const Params& p)
: LLView(p),
mMin(p.min),
mMax(p.max),
mPerSec(true),
mPrecision(p.precision),
mValue(p.value),
mStatp(p.stat.legacy_stat),
mF32Statp(p.stat.f32_stat),
mS32Statp(p.stat.s32_stat)
{
mStatp = NULL;
setToolTip(p.name());
mNumThresholds = 3;
mThresholdColors[0] = LLColor4(0.f, 1.f, 0.f, 1.f);
mThresholdColors[1] = LLColor4(1.f, 1.f, 0.f, 1.f);
mThresholdColors[2] = LLColor4(1.f, 0.f, 0.f, 1.f);
mThresholdColors[3] = LLColor4(1.f, 0.f, 0.f, 1.f);
mThresholds[0] = 50.f;
mThresholds[1] = 75.f;
mThresholds[2] = 100.f;
mMin = 0.f;
mMax = 125.f;
mPerSec = TRUE;
mValue = 0.f;
mPrecision = 0;
for(LLInitParam::ParamIterator<ThresholdParams>::const_iterator it = p.thresholds.threshold.begin(), end_it = p.thresholds.threshold.end();
it != end_it;
++it)
{
mThresholds.push_back(Threshold(it->value(), it->color));
}
//mThresholdColors[0] = LLColor4(0.f, 1.f, 0.f, 1.f);
//mThresholdColors[1] = LLColor4(1.f, 1.f, 0.f, 1.f);
//mThresholdColors[2] = LLColor4(1.f, 0.f, 0.f, 1.f);
//mThresholdColors[3] = LLColor4(1.f, 0.f, 0.f, 1.f);
//mThresholds[0] = 50.f;
//mThresholds[1] = 75.f;
//mThresholds[2] = 100.f;
}
void LLStatGraph::draw()
@ -74,6 +84,33 @@ void LLStatGraph::draw()
mValue = mStatp->getMean();
}
}
else if (mF32Statp)
{
LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
if (mPerSec)
{
mValue = sampler->getSum(*mF32Statp) / sampler->getSampleTime();
}
else
{
mValue = sampler->getSum(*mF32Statp);
}
}
else if (mS32Statp)
{
LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
if (mPerSec)
{
mValue = sampler->getSum(*mS32Statp) / sampler->getSampleTime();
}
else
{
mValue = sampler->getSum(*mS32Statp);
}
}
frac = (mValue - mMin) / range;
frac = llmax(0.f, frac);
frac = llmin(1.f, frac);
@ -91,18 +128,21 @@ void LLStatGraph::draw()
LLColor4 color;
S32 i;
for (i = 0; i < mNumThresholds - 1; i++)
{
if (mThresholds[i] > mValue)
{
break;
}
}
//S32 i;
//for (i = 0; i < mNumThresholds - 1; i++)
//{
// if (mThresholds[i] > mValue)
// {
// break;
// }
//}
//gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
// LLUIColorTable::instance().getColor("ColorDropShadow"),
// (S32) gSavedSettings.getF32("DropShadowFloater") );
threshold_vec_t::iterator it = std::lower_bound(mThresholds.begin(), mThresholds.end(), Threshold(mValue / mMax, LLUIColor()));
if (it != mThresholds.begin())
{
it--;
}
color = LLUIColorTable::instance().getColor( "MenuDefaultBgColor" );
gGL.color4fv(color.mV);
@ -111,16 +151,11 @@ void LLStatGraph::draw()
gGL.color4fv(LLColor4::black.mV);
gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, FALSE);
color = mThresholdColors[i];
color = it->mColor;
gGL.color4fv(color.mV);
gl_rect_2d(1, llround(frac*getRect().getHeight()), getRect().getWidth() - 1, 0, TRUE);
}
void LLStatGraph::setValue(const LLSD& value)
{
mValue = (F32)value.asReal();
}
void LLStatGraph::setMin(const F32 min)
{
mMin = min;
@ -131,27 +166,3 @@ void LLStatGraph::setMax(const F32 max)
mMax = max;
}
void LLStatGraph::setStat(LLStat *statp)
{
mStatp = statp;
}
void LLStatGraph::setLabel(const std::string& label)
{
mLabel = label;
}
void LLStatGraph::setUnits(const std::string& units)
{
mUnits = units;
}
void LLStatGraph::setPrecision(const S32 precision)
{
mPrecision = precision;
}
void LLStatGraph::setThreshold(const S32 i, F32 value)
{
mThresholds[i] = value;
}

View File

@ -30,29 +30,88 @@
#include "llview.h"
#include "llframetimer.h"
#include "v4color.h"
#include "lltrace.h"
class LLStat;
class LLStatGraph : public LLView
{
public:
LLStatGraph(const LLView::Params&);
struct ThresholdParams : public LLInitParam::Block<ThresholdParams>
{
Mandatory<F32> value;
Optional<LLUIColor> color;
virtual void draw();
ThresholdParams()
: value("value"),
color("color", LLColor4::white)
{}
};
struct Thresholds : public LLInitParam::Block<Thresholds>
{
Multiple<ThresholdParams> threshold;
Thresholds()
: threshold("threshold")
{}
};
struct StatParams : public LLInitParam::ChoiceBlock<StatParams>
{
Alternative<LLStat*> legacy_stat;
Alternative<LLTrace::Stat<F32>* > f32_stat;
Alternative<LLTrace::Stat<S32>* > s32_stat;
};
struct Params : public LLInitParam::Block<Params, LLView::Params>
{
Mandatory<StatParams> stat;
Optional<std::string> label,
units;
Optional<S32> precision;
Optional<F32> min,
max;
Optional<bool> per_sec;
Optional<F32> value;
Optional<Thresholds> thresholds;
Params()
: stat("stat"),
label("label"),
units("units"),
precision("precision", 0),
min("min", 0.f),
max("max", 125.f),
per_sec("per_sec", true),
value("value", 0.f),
thresholds("thresholds")
{
Thresholds _thresholds;
_thresholds.threshold.add(ThresholdParams().value(0.f).color(LLColor4::green))
.add(ThresholdParams().value(0.33f).color(LLColor4::yellow))
.add(ThresholdParams().value(0.5f).color(LLColor4::red))
.add(ThresholdParams().value(0.75f).color(LLColor4::red));
thresholds = _thresholds;
}
};
LLStatGraph(const Params&);
void setLabel(const std::string& label);
void setUnits(const std::string& units);
void setPrecision(const S32 precision);
void setStat(LLStat *statp);
void setThreshold(const S32 i, F32 value);
void setMin(const F32 min);
void setMax(const F32 max);
virtual void draw();
/*virtual*/ void setValue(const LLSD& value);
LLStat *mStatp;
BOOL mPerSec;
private:
LLStat* mStatp;
LLTrace::Stat<F32>* mF32Statp;
LLTrace::Stat<S32>* mS32Statp;
BOOL mPerSec;
F32 mValue;
F32 mMin;
@ -62,9 +121,25 @@ private:
std::string mUnits;
S32 mPrecision; // Num of digits of precision after dot
S32 mNumThresholds;
F32 mThresholds[4];
LLColor4 mThresholdColors[4];
struct Threshold
{
Threshold(F32 value, const LLUIColor& color)
: mValue(value),
mColor(color)
{}
F32 mValue;
LLUIColor mColor;
bool operator <(const Threshold& other)
{
return mValue < other.mValue;
}
};
typedef std::vector<Threshold> threshold_vec_t;
threshold_vec_t mThresholds;
//S32 mNumThresholds;
//F32 mThresholds[4];
//LLColor4 mThresholdColors[4];
};
#endif // LL_LLSTATGRAPH_H

View File

@ -198,10 +198,10 @@ BOOL LLStatusBar::postBuild()
sgp.rect(r);
sgp.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
sgp.mouse_opaque(false);
sgp.stat.f32_stat(&STAT_KBIT);
sgp.units("Kbps");
sgp.precision(0);
mSGBandwidth = LLUICtrlFactory::create<LLStatGraph>(sgp);
mSGBandwidth->setStat(&LLViewerStats::getInstance()->mKBitStat);
mSGBandwidth->setUnits("Kbps");
mSGBandwidth->setPrecision(0);
addChild(mSGBandwidth);
x -= SIM_STAT_WIDTH + 2;
@ -212,17 +212,20 @@ BOOL LLStatusBar::postBuild()
pgp.rect(r);
pgp.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
pgp.mouse_opaque(false);
pgp.stat.legacy_stat(&LLViewerStats::getInstance()->mPacketsLostPercentStat);
pgp.units("%");
pgp.min(0.f);
pgp.max(5.f);
pgp.precision(1);
pgp.per_sec(false);
LLStatGraph::Thresholds thresholds;
thresholds.threshold.add(LLStatGraph::ThresholdParams().value(0.1).color(LLColor4::green))
.add(LLStatGraph::ThresholdParams().value(0.25f).color(LLColor4::yellow))
.add(LLStatGraph::ThresholdParams().value(0.6f).color(LLColor4::red));
pgp.thresholds(thresholds);
mSGPacketLoss = LLUICtrlFactory::create<LLStatGraph>(pgp);
mSGPacketLoss->setStat(&LLViewerStats::getInstance()->mPacketsLostPercentStat);
mSGPacketLoss->setUnits("%");
mSGPacketLoss->setMin(0.f);
mSGPacketLoss->setMax(5.f);
mSGPacketLoss->setThreshold(0, 0.5f);
mSGPacketLoss->setThreshold(1, 1.f);
mSGPacketLoss->setThreshold(2, 3.f);
mSGPacketLoss->setPrecision(1);
mSGPacketLoss->mPerSec = FALSE;
addChild(mSGPacketLoss);
mPanelVolumePulldown = new LLPanelVolumePulldown();
@ -252,9 +255,9 @@ void LLStatusBar::refresh()
F32 bwtotal = gViewerThrottle.getMaxBandwidth() / 1000.f;
mSGBandwidth->setMin(0.f);
mSGBandwidth->setMax(bwtotal*1.25f);
mSGBandwidth->setThreshold(0, bwtotal*0.75f);
mSGBandwidth->setThreshold(1, bwtotal);
mSGBandwidth->setThreshold(2, bwtotal);
//mSGBandwidth->setThreshold(0, bwtotal*0.75f);
//mSGBandwidth->setThreshold(1, bwtotal);
//mSGBandwidth->setThreshold(2, bwtotal);
}
// update clock every 10 seconds

View File

@ -62,6 +62,13 @@
#include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived
LLTrace::Stat<F32> STAT_KBIT("kbitstat"),
STAT_LAYERS_KBIT("layerskbitstat"),
STAT_OBJECT_KBIT("objectkbitstat"),
STAT_ASSET_KBIT("assetkbitstat"),
STAT_TEXTURE_KBIT("texturekbitstat");
class StatAttributes
{
public:
@ -198,11 +205,6 @@ const StatAttributes STAT_INFO[LLViewerStats::ST_COUNT] =
};
LLViewerStats::LLViewerStats() :
mKBitStat("kbitstat"),
mLayersKBitStat("layerskbitstat"),
mObjectKBitStat("objectkbitstat"),
mAssetKBitStat("assetkbitstat"),
mTextureKBitStat("texturekbitstat"),
mVFSPendingOperations("vfspendingoperations"),
mFPSStat("fpsstat"),
mPacketsInStat("packetsinstat"),
@ -261,7 +263,8 @@ LLViewerStats::LLViewerStats() :
mNumNewObjectsStat("numnewobjectsstat"),
mNumSizeCulledStat("numsizeculledstat"),
mNumVisCulledStat("numvisculledstat"),
mLastTimeDiff(0.0)
mLastTimeDiff(0.0),
mSampler(LLThread::getTraceData()->createSampler())
{
for (S32 i = 0; i < ST_COUNT; i++)
{
@ -274,17 +277,18 @@ LLViewerStats::LLViewerStats() :
}
mAgentPositionSnaps.reset();
mSampler->start();
}
LLViewerStats::~LLViewerStats()
{
delete mSampler;
}
void LLViewerStats::resetStats()
{
LLViewerStats& stats = LLViewerStats::instance();
stats.mKBitStat.reset();
stats.mLayersKBitStat.reset();
stats.mObjectKBitStat.reset();
stats.mTextureKBitStat.reset();
stats.mVFSPendingOperations.reset();
stats.mAssetKBitStat.reset();
stats.mPacketsInStat.reset();
stats.mPacketsLostStat.reset();
stats.mPacketsOutStat.reset();
@ -463,10 +467,13 @@ void update_statistics()
stats.mFPSStat.addValue(1);
F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
stats.mLayersKBitStat.addValue(layer_bits/1024.f);
stats.mObjectKBitStat.addValue(gObjectBits/1024.f);
STAT_LAYERS_KBIT.sample(layer_bits/1024.f);
//stats.mLayersKBitStat.addValue(layer_bits/1024.f);
STAT_OBJECT_KBIT.sample(gObjectBits/1024.f);
//stats.mObjectKBitStat.addValue(gObjectBits/1024.f);
stats.mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending());
stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
STAT_ASSET_KBIT.sample(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
//stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
gTransferManager.resetTransferBitsIn(LLTCT_ASSET);
if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)
@ -503,7 +510,8 @@ void update_statistics()
static LLFrameTimer texture_stats_timer;
if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
{
stats.mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
STAT_TEXTURE_KBIT.sample(LLViewerTextureList::sTextureBits/1024.f);
//stats.mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets);
gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8;
LLViewerTextureList::sTextureBits = 0;

View File

@ -29,16 +29,18 @@
#include "llstat.h"
#include "lltextureinfo.h"
#include "lltracesampler.h"
extern LLTrace::Stat<F32> STAT_KBIT,
STAT_LAYERS_KBIT,
STAT_OBJECT_KBIT,
STAT_ASSET_KBIT,
STAT_TEXTURE_KBIT;
class LLViewerStats : public LLSingleton<LLViewerStats>
{
public:
LLStat mKBitStat,
mLayersKBitStat,
mObjectKBitStat,
mAssetKBitStat,
mTextureKBitStat,
mVFSPendingOperations,
LLStat mVFSPendingOperations,
mFPSStat,
mPacketsInStat,
mPacketsLostStat,
@ -110,7 +112,9 @@ public:
mNumVisCulledStat;
void resetStats();
public:
// If you change this, please also add a corresponding text label in llviewerstats.cpp
enum EStatType
{
@ -177,6 +181,7 @@ public:
};
LLViewerStats();
~LLViewerStats();
// all return latest value of given stat
F64 getStat(EStatType type) const;
@ -292,8 +297,11 @@ public:
static void recordPhaseStat(const std::string& phase_name, F32 value);
};
LLTrace::Sampler* getSampler() { return mSampler; }
private:
F64 mStats[ST_COUNT];
LLTrace::Sampler* mSampler;
F64 mLastTimeDiff; // used for time stat updates
};

View File

@ -622,7 +622,9 @@ void LLViewerTextureList::updateImages(F32 max_time)
}
cleared = FALSE;
LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec());
LLTrace::Sampler* sampler = LLThread::getTraceData()->getPrimarySampler();
LLAppViewer::getTextureFetch()->setTextureBandwidth(sampler->getMean(STAT_TEXTURE_KBIT) / sampler->getSampleTime());
LLViewerStats::getInstance()->mNumImagesStat.addValue(sNumImages);
LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);

View File

@ -704,7 +704,8 @@ void LLWorld::updateNetStats()
S32 actual_out_bits = gMessageSystem->mPacketRing.getAndResetActualOutBits();
LLViewerStats::getInstance()->mActualInKBitStat.addValue(actual_in_bits/1024.f);
LLViewerStats::getInstance()->mActualOutKBitStat.addValue(actual_out_bits/1024.f);
LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f);
STAT_KBIT.sample(bits/1024.f);
//LLViewerStats::getInstance()->mKBitStat.addValue(bits/1024.f);
LLViewerStats::getInstance()->mPacketsInStat.addValue(packets_in);
LLViewerStats::getInstance()->mPacketsOutStat.addValue(packets_out);
LLViewerStats::getInstance()->mPacketsLostStat.addValue(gMessageSystem->mDroppedPackets);