SH-4246 FIX interesting: fast timers significantly decreases framerate
removed implicit flushes on reads from recorders for better performance made sure stack timers were updated on recorder deactivate faster rendering and better ui for fast timer viewmaster
parent
1cb0c974ae
commit
d136c4c296
|
|
@ -178,43 +178,38 @@ TimeBlockTreeNode& TimeBlock::getTreeNode() const
|
|||
return *nodep;
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_TIMES("Process FastTimer Times");
|
||||
|
||||
// not thread safe, so only call on main thread
|
||||
//static
|
||||
void TimeBlock::processTimes()
|
||||
void TimeBlock::bootstrapTimerTree()
|
||||
{
|
||||
LLFastTimer _(FTM_PROCESS_TIMES);
|
||||
get_clock_count(); // good place to calculate clock frequency
|
||||
U64 cur_time = getCPUClockCount64();
|
||||
|
||||
// set up initial tree
|
||||
for (LLInstanceTracker<TimeBlock>::instance_iter begin_it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(), it = begin_it;
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
TimeBlock& timer = *it;
|
||||
if (&timer == &TimeBlock::getRootTimeBlock()) continue;
|
||||
|
||||
|
||||
// bootstrap tree construction by attaching to last timer to be on stack
|
||||
// when this timer was called
|
||||
if (timer.getParent() == &TimeBlock::getRootTimeBlock())
|
||||
{
|
||||
TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
|
||||
|
||||
|
||||
if (accumulator->mLastCaller)
|
||||
{
|
||||
timer.setParent(accumulator->mLastCaller);
|
||||
accumulator->mParent = accumulator->mLastCaller;
|
||||
}
|
||||
// no need to push up tree on first use, flag can be set spuriously
|
||||
// no need to push up tree on first use, flag can be set spuriously
|
||||
accumulator->mMoveUpTree = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bump timers up tree if they have been flagged as being in the wrong place
|
||||
// do this in a bottom up order to promote descendants first before promoting ancestors
|
||||
// this preserves partial order derived from current frame's observations
|
||||
// bump timers up tree if they have been flagged as being in the wrong place
|
||||
// do this in a bottom up order to promote descendants first before promoting ancestors
|
||||
// this preserves partial order derived from current frame's observations
|
||||
void TimeBlock::incrementalUpdateTimerTree()
|
||||
{
|
||||
for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimeBlock());
|
||||
it != end_timer_tree_bottom_up();
|
||||
++it)
|
||||
|
|
@ -240,27 +235,35 @@ void TimeBlock::processTimes()
|
|||
LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
|
||||
" to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL;
|
||||
timerp->setParent(timerp->getParent()->getParent());
|
||||
accumulator->mParent = timerp->getParent();
|
||||
accumulator->mMoveUpTree = false;
|
||||
accumulator->mParent = timerp->getParent();
|
||||
accumulator->mMoveUpTree = false;
|
||||
|
||||
// don't bubble up any ancestors until descendants are done bubbling up
|
||||
// as ancestors may call this timer only on certain paths, so we want to resolve
|
||||
// child-most block locations before their parents
|
||||
// as ancestors may call this timer only on certain paths, so we want to resolve
|
||||
// child-most block locations before their parents
|
||||
it.skipAncestors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TimeBlock::updateTimes()
|
||||
{
|
||||
U64 cur_time = getCPUClockCount64();
|
||||
|
||||
// walk up stack of active timers and accumulate current time while leaving timing structures active
|
||||
BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();
|
||||
BlockTimer* cur_timer = stack_record->mActiveTimer;
|
||||
TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
|
||||
BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();
|
||||
BlockTimer* cur_timer = stack_record->mActiveTimer;
|
||||
TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
|
||||
|
||||
while(cur_timer
|
||||
&& cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self
|
||||
{
|
||||
U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
|
||||
accumulator->mTotalTimeCounter += cumulative_time_delta - (accumulator->mTotalTimeCounter - cur_timer->mBlockStartTotalTimeCounter);
|
||||
accumulator->mTotalTimeCounter += cumulative_time_delta
|
||||
- (accumulator->mTotalTimeCounter
|
||||
- cur_timer->mBlockStartTotalTimeCounter);
|
||||
accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime;
|
||||
stack_record->mChildTime = 0;
|
||||
|
||||
|
|
@ -268,11 +271,28 @@ void TimeBlock::processTimes()
|
|||
cur_timer->mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;
|
||||
|
||||
stack_record = &cur_timer->mParentTimerData;
|
||||
accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
|
||||
cur_timer = stack_record->mActiveTimer;
|
||||
accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
|
||||
cur_timer = stack_record->mActiveTimer;
|
||||
|
||||
stack_record->mChildTime += cumulative_time_delta;
|
||||
}
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_PROCESS_TIMES("Process FastTimer Times");
|
||||
|
||||
// not thread safe, so only call on main thread
|
||||
//static
|
||||
void TimeBlock::processTimes()
|
||||
{
|
||||
LLFastTimer _(FTM_PROCESS_TIMES);
|
||||
get_clock_count(); // good place to calculate clock frequency
|
||||
|
||||
// set up initial tree
|
||||
bootstrapTimerTree();
|
||||
|
||||
incrementalUpdateTimerTree();
|
||||
|
||||
updateTimes();
|
||||
|
||||
// reset for next frame
|
||||
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
|
||||
|
|
@ -288,14 +308,13 @@ void TimeBlock::processTimes()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<TimeBlock*>::iterator TimeBlock::beginChildren()
|
||||
{
|
||||
{
|
||||
return getTreeNode().mChildren.begin();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TimeBlock*>::iterator TimeBlock::endChildren()
|
||||
{
|
||||
{
|
||||
return getTreeNode().mChildren.end();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ public:
|
|||
static void pushLog(LLSD sd);
|
||||
static void setLogLock(LLMutex* mutex);
|
||||
static void writeLog(std::ostream& os);
|
||||
static void updateTimes();
|
||||
|
||||
// dumps current cumulative frame stats to log
|
||||
// call nextFrame() to reset timers
|
||||
|
|
@ -262,6 +263,9 @@ public:
|
|||
// can be called multiple times in a frame, at any point
|
||||
static void processTimes();
|
||||
|
||||
static void bootstrapTimerTree();
|
||||
static void incrementalUpdateTimerTree();
|
||||
|
||||
// call this once a frame to periodically log timers
|
||||
static void logStats();
|
||||
|
||||
|
|
|
|||
|
|
@ -157,12 +157,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void flush()
|
||||
void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
|
||||
{
|
||||
llassert(mStorageSize >= sNextStorageSlot);
|
||||
for (size_t i = 0; i < sNextStorageSlot; i++)
|
||||
{
|
||||
mStorage[i].flush();
|
||||
mStorage[i].flush(time_stamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,7 +380,7 @@ public:
|
|||
mLastValue = other ? other->mLastValue : 0;
|
||||
}
|
||||
|
||||
void flush() {}
|
||||
void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
|
||||
|
||||
F64 getSum() const { return mSum; }
|
||||
F64 getMin() const { return mMin; }
|
||||
|
|
@ -512,9 +512,8 @@ public:
|
|||
mHasValue = other ? other->mHasValue : false;
|
||||
}
|
||||
|
||||
void flush()
|
||||
void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
|
||||
{
|
||||
LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
|
||||
LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;
|
||||
|
||||
if (mHasValue)
|
||||
|
|
@ -579,7 +578,7 @@ public:
|
|||
mSum = 0;
|
||||
}
|
||||
|
||||
void flush() {}
|
||||
void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
|
||||
|
||||
F64 getSum() const { return mSum; }
|
||||
|
||||
|
|
@ -614,7 +613,7 @@ public:
|
|||
TimeBlockAccumulator();
|
||||
void addSamples(const self_t& other, bool /*append*/);
|
||||
void reset(const self_t* other);
|
||||
void flush() {}
|
||||
void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}
|
||||
|
||||
//
|
||||
// members
|
||||
|
|
@ -780,10 +779,10 @@ struct MemStatAccumulator
|
|||
mDeallocatedCount = 0;
|
||||
}
|
||||
|
||||
void flush()
|
||||
void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)
|
||||
{
|
||||
mSize.flush();
|
||||
mChildSize.flush();
|
||||
mSize.flush(time_stamp);
|
||||
mChildSize.flush(time_stamp);
|
||||
}
|
||||
|
||||
SampleAccumulator mSize,
|
||||
|
|
|
|||
|
|
@ -107,7 +107,9 @@ void RecordingBuffers::reset(RecordingBuffers* other)
|
|||
|
||||
void RecordingBuffers::flush()
|
||||
{
|
||||
mSamples.flush();
|
||||
LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
|
||||
|
||||
mSamples.flush(time_stamp);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -205,7 +207,6 @@ void Recording::mergeRecording( const Recording& other)
|
|||
LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat)
|
||||
{
|
||||
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
|
||||
update();
|
||||
return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
|
||||
/ (F64)LLTrace::TimeBlock::countsPerSecond();
|
||||
}
|
||||
|
|
@ -213,14 +214,12 @@ LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumul
|
|||
LLUnit<F64, LLUnits::Seconds> 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;
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +227,6 @@ LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccu
|
|||
{
|
||||
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
|
||||
|
||||
update();
|
||||
return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
|
||||
/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value());
|
||||
}
|
||||
|
|
@ -237,105 +235,88 @@ LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccu
|
|||
{
|
||||
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
|
||||
|
||||
update();
|
||||
return (F64)(accumulator.mSelfTimeCounter)
|
||||
/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value());
|
||||
}
|
||||
|
||||
F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat)
|
||||
{
|
||||
update();
|
||||
return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds.value();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mSize.getMin();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mSize.getMean();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mSize.getMax();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mSize.getStandardDeviation();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getLastValue(const TraceType<MemStatAccumulator>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mSize.getLastValue();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMin();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMean();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMax();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
|
||||
{
|
||||
update();
|
||||
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getStandardDeviation();
|
||||
}
|
||||
|
||||
LLUnit<F64, LLUnits::Bytes> 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.value())
|
||||
|
|
@ -344,79 +325,66 @@ F64 Recording::getPerSec( const TraceType<CountAccumulator>& stat )
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringU
|
|||
if (mActiveRecordings.empty()) return mActiveRecordings.rend();
|
||||
|
||||
mActiveRecordings.back()->mPartialRecording.flush();
|
||||
TimeBlock::updateTimes();
|
||||
|
||||
active_recording_list_t::reverse_iterator it, end_it;
|
||||
for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend();
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ namespace tut
|
|||
LLUnit<F32, Quatloos> float_quatloos;
|
||||
ensure(float_quatloos == 0.f);
|
||||
|
||||
LLUnit<F32, Quatloos> float_initialize_quatloos(1);
|
||||
ensure(float_initialize_quatloos == 1.f);
|
||||
|
||||
LLUnit<S32, Quatloos> int_quatloos;
|
||||
ensure(int_quatloos == 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@
|
|||
|
||||
#include "llviewerwindow.h"
|
||||
#include "llrect.h"
|
||||
#include "llcombobox.h"
|
||||
#include "llerror.h"
|
||||
#include "llgl.h"
|
||||
#include "llimagepng.h"
|
||||
#include "llrender.h"
|
||||
#include "llrendertarget.h"
|
||||
#include "lllocalcliprect.h"
|
||||
#include "lllayoutstack.h"
|
||||
#include "llmath.h"
|
||||
#include "llfontgl.h"
|
||||
#include "llsdserialize.h"
|
||||
|
|
@ -59,6 +61,8 @@ using namespace LLTrace;
|
|||
static const S32 MAX_VISIBLE_HISTORY = 12;
|
||||
static const S32 LINE_GRAPH_HEIGHT = 240;
|
||||
static const S32 MIN_BAR_HEIGHT = 3;
|
||||
static const S32 RUNNING_AVERAGE_WIDTH = 100;
|
||||
static const S32 NUM_FRAMES_HISTORY = 256;
|
||||
|
||||
std::vector<TimeBlock*> ft_display_idx; // line of table entry for display purposes (for collapse)
|
||||
|
||||
|
|
@ -95,17 +99,15 @@ LLFastTimerView::LLFastTimerView(const LLSD& key)
|
|||
: LLFloater(key),
|
||||
mHoverTimer(NULL),
|
||||
mDisplayMode(0),
|
||||
mDisplayCenter(ALIGN_CENTER),
|
||||
mDisplayCalls(false),
|
||||
mDisplayHz(false),
|
||||
mDisplayType(TIME),
|
||||
mScrollIndex(0),
|
||||
mHoverID(NULL),
|
||||
mHoverBarIndex(-1),
|
||||
mStatsIndex(-1),
|
||||
mPauseHistory(false),
|
||||
mRecording(512)
|
||||
mRecording(NUM_FRAMES_HISTORY)
|
||||
{
|
||||
mTimerBarRows.resize(512);
|
||||
mTimerBarRows.resize(NUM_FRAMES_HISTORY);
|
||||
}
|
||||
|
||||
LLFastTimerView::~LLFastTimerView()
|
||||
|
|
@ -172,7 +174,7 @@ BOOL LLFastTimerView::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
|||
|
||||
TimeBlock* LLFastTimerView::getLegendID(S32 y)
|
||||
{
|
||||
S32 idx = (mBarRect.mTop - y) / (LLFontGL::getFontMonospace()->getLineHeight()+2) - 1;
|
||||
S32 idx = (mLegendRect.mTop - y) / (LLFontGL::getFontMonospace()->getLineHeight() + 2);
|
||||
|
||||
if (idx >= 0 && idx < (S32)ft_display_idx.size())
|
||||
{
|
||||
|
|
@ -208,26 +210,6 @@ BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask)
|
|||
//left click drills down by expanding timers
|
||||
mHoverTimer->setCollapsed(false);
|
||||
}
|
||||
else if (mask & MASK_ALT)
|
||||
{
|
||||
if (mask & MASK_CONTROL)
|
||||
{
|
||||
mDisplayHz = !mDisplayHz;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDisplayCalls = !mDisplayCalls;
|
||||
}
|
||||
}
|
||||
else if (mask & MASK_SHIFT)
|
||||
{
|
||||
if (++mDisplayMode > 3)
|
||||
mDisplayMode = 0;
|
||||
}
|
||||
else if (mask & MASK_CONTROL)
|
||||
{
|
||||
mDisplayCenter = (ChildAlignment)((mDisplayCenter + 1) % ALIGN_COUNT);
|
||||
}
|
||||
else if (mGraphRect.pointInRect(x, y))
|
||||
{
|
||||
gFocusMgr.setMouseCapture(this);
|
||||
|
|
@ -260,7 +242,10 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
|
|||
|
||||
if(mPauseHistory && mBarRect.pointInRect(x, y))
|
||||
{
|
||||
mHoverBarIndex = llmin((mBarRect.mTop - y) / (mBarRect.getHeight() / (MAX_VISIBLE_HISTORY + 2)) - 1,
|
||||
//const S32 bars_top = mBarRect.mTop;
|
||||
const S32 bars_top = mBarRect.mTop - ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4);
|
||||
|
||||
mHoverBarIndex = llmin((bars_top - y) / (mBarRect.getHeight() / (MAX_VISIBLE_HISTORY + 2)) - 1,
|
||||
(S32)mRecording.getNumRecordedPeriods() - 1,
|
||||
MAX_VISIBLE_HISTORY);
|
||||
if (mHoverBarIndex == 0)
|
||||
|
|
@ -272,25 +257,33 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
|
|||
mHoverBarIndex = 0;
|
||||
}
|
||||
|
||||
TimerBarRow& row = mHoverBarIndex == 0 ? mAverageTimerRow : mTimerBarRows[mHoverBarIndex - 1];
|
||||
TimerBarRow& row = mHoverBarIndex == 0 ? mAverageTimerRow : mTimerBarRows[mScrollIndex + mHoverBarIndex - 1];
|
||||
|
||||
TimerBar* hover_bar = NULL;
|
||||
LLUnit<F32, LLUnits::Seconds> mouse_time_offset = ((F32)(x - mBarRect.mLeft) / (F32)mBarRect.getWidth()) * mTotalTimeDisplay;
|
||||
for (std::vector<TimerBar>::iterator it = row.mBars.begin(), end_it = row.mBars.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
for (int bar_index = 0, end_index = LLInstanceTracker<LLTrace::TimeBlock>::instanceCount();
|
||||
bar_index < end_index;
|
||||
++bar_index)
|
||||
{
|
||||
if (it->mSelfStart > mouse_time_offset)
|
||||
TimerBar& bar = row.mBars[bar_index];
|
||||
if (bar.mSelfStart > mouse_time_offset)
|
||||
{
|
||||
break;
|
||||
}
|
||||
hover_bar = &(*it);
|
||||
if (bar.mSelfEnd > mouse_time_offset)
|
||||
{
|
||||
hover_bar = &bar;
|
||||
if (bar.mTimeBlock->getCollapsed())
|
||||
{
|
||||
// stop on first collapsed timeblock, since we can't select any children
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hover_bar)
|
||||
{
|
||||
mHoverID = hover_bar->mTimeBlock;
|
||||
mHoverTimer = mHoverID;
|
||||
if (mHoverTimer != mHoverID)
|
||||
{
|
||||
// could be that existing tooltip is for a parent and is thus
|
||||
|
|
@ -300,7 +293,7 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask)
|
|||
mHoverTimer = mHoverID;
|
||||
mToolTipRect.set(mBarRect.mLeft + (hover_bar->mSelfStart / mTotalTimeDisplay) * mBarRect.getWidth(),
|
||||
row.mTop,
|
||||
mBarRect.mLeft + (hover_bar->mSelfStart / mTotalTimeDisplay) * mBarRect.getWidth(),
|
||||
mBarRect.mLeft + (hover_bar->mSelfEnd / mTotalTimeDisplay) * mBarRect.getWidth(),
|
||||
row.mBottom);
|
||||
}
|
||||
}
|
||||
|
|
@ -324,7 +317,7 @@ static std::string get_tooltip(TimeBlock& timer, S32 history_index, PeriodicReco
|
|||
if (history_index == 0)
|
||||
{
|
||||
// by default, show average number of call
|
||||
tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)LLUnit<F64, LLUnits::Milliseconds>(frame_recording.getPeriodMean(timer)).value(), (S32)frame_recording.getPeriodMean(timer.callCount()));
|
||||
tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)LLUnit<F64, LLUnits::Milliseconds>(frame_recording.getPeriodMean (timer, RUNNING_AVERAGE_WIDTH)).value(), (S32)frame_recording.getPeriodMean(timer.callCount(), RUNNING_AVERAGE_WIDTH));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -397,22 +390,34 @@ void LLFastTimerView::draw()
|
|||
mTimerBarRows.push_front(TimerBarRow());
|
||||
}
|
||||
|
||||
mDisplayMode = llclamp(getChild<LLComboBox>("time_scale_combo")->getCurrentIndex(), 0, 3);
|
||||
mDisplayType = (EDisplayType)llclamp(getChild<LLComboBox>("metric_combo")->getCurrentIndex(), 0, 2);
|
||||
|
||||
generateUniqueColors();
|
||||
|
||||
LLView::drawChildren();
|
||||
//getChild<LLLayoutStack>("timer_bars_stack")->updateLayout();
|
||||
//getChild<LLLayoutStack>("legend_stack")->updateLayout();
|
||||
LLView* bars_panel = getChildView("bars_panel");
|
||||
bars_panel->localRectToOtherView(bars_panel->getLocalRect(), &mBarRect, this);
|
||||
|
||||
LLView* lines_panel = getChildView("lines_panel");
|
||||
lines_panel->localRectToOtherView(lines_panel->getLocalRect(), &mGraphRect, this);
|
||||
|
||||
LLView* legend_panel = getChildView("legend");
|
||||
legend_panel->localRectToOtherView(legend_panel->getLocalRect(), &mLegendRect, this);
|
||||
|
||||
// Draw the window background
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
gl_rect_2d(getLocalRect(), LLColor4(0.f, 0.f, 0.f, 0.25f));
|
||||
|
||||
S32 y = drawHelp(getRect().getHeight() - MARGIN);
|
||||
drawLegend(y - ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 2));
|
||||
drawHelp(getRect().getHeight() - MARGIN);
|
||||
drawLegend();
|
||||
|
||||
// update rectangle that includes timer bars
|
||||
const S32 LEGEND_WIDTH = 220;
|
||||
|
||||
mBarRect.mLeft = MARGIN + LEGEND_WIDTH + 8;
|
||||
mBarRect.mTop = y;
|
||||
mBarRect.mRight = getRect().getWidth() - MARGIN;
|
||||
mBarRect.mBottom = MARGIN + LINE_GRAPH_HEIGHT;
|
||||
//mBarRect.mLeft = MARGIN + LEGEND_WIDTH + 8;
|
||||
//mBarRect.mTop = y;
|
||||
//mBarRect.mRight = getRect().getWidth() - MARGIN;
|
||||
//mBarRect.mBottom = MARGIN + LINE_GRAPH_HEIGHT;
|
||||
|
||||
drawBars();
|
||||
drawLineGraph();
|
||||
|
|
@ -433,7 +438,8 @@ void LLFastTimerView::onOpen(const LLSD& key)
|
|||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
it->mBars.clear();
|
||||
delete []it->mBars;
|
||||
it->mBars = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -993,7 +999,7 @@ void LLFastTimerView::printLineStats()
|
|||
LLUnit<F32, LLUnits::Seconds> ticks;
|
||||
if (mStatsIndex == 0)
|
||||
{
|
||||
ticks = mRecording.getPeriodMean(*idp);
|
||||
ticks = mRecording.getPeriodMean(*idp, RUNNING_AVERAGE_WIDTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1019,8 +1025,6 @@ void LLFastTimerView::drawLineGraph()
|
|||
{
|
||||
LLFastTimer _(FTM_DRAW_LINE_GRAPH);
|
||||
//draw line graph history
|
||||
S32 x = mBarRect.mLeft;
|
||||
S32 y = LINE_GRAPH_HEIGHT;
|
||||
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
|
||||
LLLocalClipRect clip(mGraphRect);
|
||||
|
||||
|
|
@ -1029,21 +1033,6 @@ void LLFastTimerView::drawLineGraph()
|
|||
static U32 max_calls = 0;
|
||||
static F32 alpha_interp = 0.f;
|
||||
|
||||
//display y-axis range
|
||||
std::string axis_label;
|
||||
if (mDisplayCalls)
|
||||
axis_label = llformat("%d calls", (int)max_calls);
|
||||
else if (mDisplayHz)
|
||||
axis_label = llformat("%d Hz", (int)(1.f / max_time.value()));
|
||||
else
|
||||
axis_label = llformat("%4.2f ms", LLUnit<F32, LLUnits::Milliseconds>(max_time).value());
|
||||
|
||||
x = mGraphRect.mRight - LLFontGL::getFontMonospace()->getWidth(axis_label)-5;
|
||||
y = mGraphRect.mTop - LLFontGL::getFontMonospace()->getLineHeight();
|
||||
|
||||
LLFontGL::getFontMonospace()->renderUTF8(axis_label, 0, x, y, LLColor4::white,
|
||||
LLFontGL::LEFT, LLFontGL::TOP);
|
||||
|
||||
//highlight visible range
|
||||
{
|
||||
S32 first_frame = mRecording.getNumRecordedPeriods() - mScrollIndex;
|
||||
|
|
@ -1059,7 +1048,7 @@ void LLFastTimerView::drawLineGraph()
|
|||
|
||||
if (mHoverBarIndex > 0)
|
||||
{
|
||||
S32 bar_frame = first_frame - mHoverBarIndex - 1;
|
||||
S32 bar_frame = first_frame - (mScrollIndex + mHoverBarIndex) - 1;
|
||||
F32 bar = (F32) mGraphRect.mLeft + frame_delta*bar_frame;
|
||||
|
||||
gGL.color4f(0.5f,0.5f,0.5f,1);
|
||||
|
|
@ -1090,6 +1079,7 @@ void LLFastTimerView::drawLineGraph()
|
|||
const F32 * col = sTimerColors[idp->getIndex()].mV;// ft_display_table[idx].color->mV;
|
||||
|
||||
F32 alpha = 1.f;
|
||||
bool is_hover_timer = true;
|
||||
|
||||
if (mHoverID != NULL &&
|
||||
mHoverID != idp)
|
||||
|
|
@ -1097,11 +1087,15 @@ void LLFastTimerView::drawLineGraph()
|
|||
if (idp->getParent() != mHoverID)
|
||||
{
|
||||
alpha = alpha_interp;
|
||||
is_hover_timer = false;
|
||||
}
|
||||
}
|
||||
|
||||
gGL.color4f(col[0], col[1], col[2], alpha);
|
||||
gGL.begin(LLRender::TRIANGLE_STRIP);
|
||||
F32 call_scale_factor = (F32)mGraphRect.getHeight() / (F32)max_calls;
|
||||
F32 time_scale_factor = (F32)mGraphRect.getHeight() / max_time.value();
|
||||
F32 hz_scale_factor = (F32) mGraphRect.getHeight() / (1.f / max_time.value());
|
||||
for (U32 j = mRecording.getNumRecordedPeriods();
|
||||
j > 0;
|
||||
j--)
|
||||
|
|
@ -1110,16 +1104,26 @@ void LLFastTimerView::drawLineGraph()
|
|||
LLUnit<F32, LLUnits::Seconds> time = llmax(recording.getSum(*idp), LLUnit<F64, LLUnits::Seconds>(0.000001));
|
||||
U32 calls = recording.getSum(idp->callCount());
|
||||
|
||||
if (alpha == 1.f)
|
||||
if (is_hover_timer)
|
||||
{
|
||||
//normalize to highlighted timer
|
||||
cur_max = llmax(cur_max, time);
|
||||
cur_max_calls = llmax(cur_max_calls, calls);
|
||||
}
|
||||
F32 x = mGraphRect.mRight - j * (F32)(mGraphRect.getWidth())/(mRecording.getNumRecordedPeriods()-1);
|
||||
F32 y = mDisplayHz
|
||||
? mGraphRect.mBottom + (1.f / time.value()) * ((F32) mGraphRect.getHeight() / (1.f / max_time.value()))
|
||||
: mGraphRect.mBottom + time / max_time * (F32)mGraphRect.getHeight();
|
||||
F32 y;
|
||||
switch(mDisplayType)
|
||||
{
|
||||
case TIME:
|
||||
y = mGraphRect.mBottom + time.value() * time_scale_factor;
|
||||
break;
|
||||
case CALLS:
|
||||
y = mGraphRect.mBottom + (F32)calls * call_scale_factor;
|
||||
break;
|
||||
case HZ:
|
||||
y = mGraphRect.mBottom + (1.f / time.value()) * hz_scale_factor;
|
||||
break;
|
||||
}
|
||||
gGL.vertex2f(x,y);
|
||||
gGL.vertex2f(x,mGraphRect.mBottom);
|
||||
}
|
||||
|
|
@ -1140,7 +1144,7 @@ void LLFastTimerView::drawLineGraph()
|
|||
|
||||
//interpolate towards new maximum
|
||||
max_time = lerp(max_time.value(), cur_max.value(), LLSmoothInterpolation::getInterpolant(0.1f));
|
||||
if (max_time - cur_max <= 1 || cur_max - max_time <= 1)
|
||||
if (llabs((max_time - cur_max).value()) <= 1)
|
||||
{
|
||||
max_time = llmax(LLUnit<F32, LLUnits::Microseconds>(1), LLUnit<F32, LLUnits::Microseconds>(cur_max));
|
||||
}
|
||||
|
|
@ -1159,8 +1163,8 @@ void LLFastTimerView::drawLineGraph()
|
|||
|
||||
if (mHoverID != NULL)
|
||||
{
|
||||
x = (mGraphRect.mRight + mGraphRect.mLeft)/2;
|
||||
y = mGraphRect.mBottom + 8;
|
||||
S32 x = (mGraphRect.mRight + mGraphRect.mLeft)/2;
|
||||
S32 y = mGraphRect.mBottom + 8;
|
||||
|
||||
LLFontGL::getFontMonospace()->renderUTF8(
|
||||
mHoverID->getName(),
|
||||
|
|
@ -1168,18 +1172,40 @@ void LLFastTimerView::drawLineGraph()
|
|||
x, y,
|
||||
LLColor4::white,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
//display y-axis range
|
||||
std::string axis_label;
|
||||
switch(mDisplayType)
|
||||
{
|
||||
case TIME:
|
||||
axis_label = llformat("%4.2f ms", LLUnit<F32, LLUnits::Milliseconds>(max_time).value());
|
||||
break;
|
||||
case CALLS:
|
||||
axis_label = llformat("%d calls", (int)max_calls);
|
||||
break;
|
||||
case HZ:
|
||||
axis_label = llformat("%4.2f Hz", max_time.value() ? 1.f / max_time.value() : 0.f);
|
||||
break;
|
||||
}
|
||||
|
||||
LLFontGL* font = LLFontGL::getFontMonospace();
|
||||
S32 x = mGraphRect.mRight - font->getWidth(axis_label)-5;
|
||||
S32 y = mGraphRect.mTop - font->getLineHeight();;
|
||||
|
||||
font->renderUTF8(axis_label, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
|
||||
}
|
||||
|
||||
void LLFastTimerView::drawLegend( S32 y )
|
||||
void LLFastTimerView::drawLegend()
|
||||
{
|
||||
// draw legend
|
||||
S32 dx;
|
||||
S32 x = MARGIN;
|
||||
S32 x = mLegendRect.mLeft;
|
||||
S32 y = mLegendRect.mTop;
|
||||
const S32 TEXT_HEIGHT = (S32)LLFontGL::getFontMonospace()->getLineHeight();
|
||||
|
||||
{
|
||||
LLLocalClipRect clip(LLRect(MARGIN, y, LEGEND_WIDTH, MARGIN));
|
||||
LLLocalClipRect clip(mLegendRect);
|
||||
S32 cur_line = 0;
|
||||
ft_display_idx.clear();
|
||||
std::map<TimeBlock*, S32> display_line;
|
||||
|
|
@ -1214,18 +1240,22 @@ void LLFastTimerView::drawLegend( S32 y )
|
|||
}
|
||||
else
|
||||
{
|
||||
ms = LLUnit<F64, LLUnits::Seconds>(mRecording.getPeriodMean(*idp));
|
||||
calls = (S32)mRecording.getPeriodMean(idp->callCount());
|
||||
ms = LLUnit<F64, LLUnits::Seconds>(mRecording.getPeriodMean(*idp, RUNNING_AVERAGE_WIDTH));
|
||||
calls = (S32)mRecording.getPeriodMean(idp->callCount(), RUNNING_AVERAGE_WIDTH);
|
||||
}
|
||||
|
||||
std::string timer_label;
|
||||
if (mDisplayCalls)
|
||||
{
|
||||
timer_label = llformat("%s (%d)",idp->getName().c_str(),calls);
|
||||
}
|
||||
else
|
||||
switch(mDisplayType)
|
||||
{
|
||||
case TIME:
|
||||
timer_label = llformat("%s [%.1f]",idp->getName().c_str(),ms.value());
|
||||
break;
|
||||
case CALLS:
|
||||
timer_label = llformat("%s (%d)",idp->getName().c_str(),calls);
|
||||
break;
|
||||
case HZ:
|
||||
timer_label = llformat("%.1f", ms.value() ? (1.f / ms.value()) : 0.f);
|
||||
break;
|
||||
}
|
||||
dx = (TEXT_HEIGHT+4) + get_depth(idp)*8;
|
||||
|
||||
|
|
@ -1300,36 +1330,16 @@ void LLFastTimerView::generateUniqueColors()
|
|||
}
|
||||
}
|
||||
|
||||
S32 LLFastTimerView::drawHelp( S32 y )
|
||||
void LLFastTimerView::drawHelp( S32 y )
|
||||
{
|
||||
// Draw some help
|
||||
const S32 texth = (S32)LLFontGL::getFontMonospace()->getLineHeight();
|
||||
|
||||
char modedesc[][32] = {
|
||||
"2 x Average ",
|
||||
"Max ",
|
||||
"Recent Max ",
|
||||
"100 ms "
|
||||
};
|
||||
char centerdesc[][32] = {
|
||||
"Left ",
|
||||
"Centered ",
|
||||
"Ordered "
|
||||
};
|
||||
|
||||
std::string text;
|
||||
text = llformat("Full bar = %s [Click to pause/reset] [SHIFT-Click to toggle]",modedesc[mDisplayMode]);
|
||||
LLFontGL::getFontMonospace()->renderUTF8(text, 0, MARGIN, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
|
||||
|
||||
y -= (texth + 2);
|
||||
text = llformat("Justification = %s [CTRL-Click to toggle]",centerdesc[mDisplayCenter]);
|
||||
LLFontGL::getFontMonospace()->renderUTF8(text, 0, MARGIN, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
|
||||
y -= (texth + 2);
|
||||
|
||||
LLFontGL::getFontMonospace()->renderUTF8(std::string("[Right-Click log selected] [ALT-Click toggle counts] [ALT-SHIFT-Click sub hidden]"),
|
||||
LLFontGL::getFontMonospace()->renderUTF8(std::string("[Right-Click log selected] [ALT-Click toggle counts]"),
|
||||
0, MARGIN, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP);
|
||||
y -= (texth + 2);
|
||||
return y;
|
||||
}
|
||||
|
||||
void LLFastTimerView::drawTicks()
|
||||
|
|
@ -1392,7 +1402,7 @@ void LLFastTimerView::drawBorders( S32 y, const S32 x_start, S32 bar_height, S32
|
|||
by = LINE_GRAPH_HEIGHT-dy;
|
||||
|
||||
//line graph
|
||||
mGraphRect = LLRect(x_start-5, by, getRect().getWidth()-5, 5);
|
||||
//mGraphRect = LLRect(x_start-5, by, getRect().getWidth()-5, 5);
|
||||
|
||||
gl_rect_2d(mGraphRect, FALSE);
|
||||
}
|
||||
|
|
@ -1403,7 +1413,7 @@ void LLFastTimerView::updateTotalTime()
|
|||
switch(mDisplayMode)
|
||||
{
|
||||
case 0:
|
||||
mTotalTimeDisplay = mRecording.getPeriodMean(FTM_FRAME, 100)*2;
|
||||
mTotalTimeDisplay = mRecording.getPeriodMean(FTM_FRAME, RUNNING_AVERAGE_WIDTH)*2;
|
||||
break;
|
||||
case 1:
|
||||
mTotalTimeDisplay = mRecording.getPeriodMax(FTM_FRAME);
|
||||
|
|
@ -1447,18 +1457,27 @@ void LLFastTimerView::drawBars()
|
|||
const S32 histmax = (S32)mRecording.getNumRecordedPeriods();
|
||||
|
||||
// update widths
|
||||
updateTimerBarWidths(&FTM_FRAME, mAverageTimerRow, -1);
|
||||
updateTimerBarOffsets(&FTM_FRAME, mAverageTimerRow);
|
||||
|
||||
for (S32 history_index = 1; history_index <= histmax; history_index++)
|
||||
if (!mPauseHistory)
|
||||
{
|
||||
llassert(history_index <= mTimerBarRows.size());
|
||||
TimerBarRow& row = mTimerBarRows[history_index - 1];
|
||||
if (row.mBars.empty())
|
||||
U32 bar_index = 0;
|
||||
if (!mAverageTimerRow.mBars)
|
||||
{
|
||||
row.mBars.reserve(LLInstanceTracker<LLTrace::TimeBlock>::instanceCount());
|
||||
updateTimerBarWidths(&FTM_FRAME, row, history_index);
|
||||
updateTimerBarOffsets(&FTM_FRAME, row);
|
||||
mAverageTimerRow.mBars = new TimerBar[LLInstanceTracker<LLTrace::TimeBlock>::instanceCount()];
|
||||
}
|
||||
updateTimerBarWidths(&FTM_FRAME, mAverageTimerRow, -1, bar_index);
|
||||
updateTimerBarOffsets(&FTM_FRAME, mAverageTimerRow);
|
||||
|
||||
for (S32 history_index = 1; history_index <= histmax; history_index++)
|
||||
{
|
||||
llassert(history_index <= mTimerBarRows.size());
|
||||
TimerBarRow& row = mTimerBarRows[history_index - 1];
|
||||
bar_index = 0;
|
||||
if (!row.mBars)
|
||||
{
|
||||
row.mBars = new TimerBar[LLInstanceTracker<LLTrace::TimeBlock>::instanceCount()];
|
||||
updateTimerBarWidths(&FTM_FRAME, row, history_index, bar_index);
|
||||
updateTimerBarOffsets(&FTM_FRAME, row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1492,32 +1511,28 @@ void LLFastTimerView::drawBars()
|
|||
|
||||
static LLFastTimer::DeclareTimer FTM_UPDATE_TIMER_BAR_WIDTHS("Update timer bar widths");
|
||||
|
||||
LLUnit<F32, LLUnits::Seconds> LLFastTimerView::updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, bool visible)
|
||||
LLUnit<F32, LLUnits::Seconds> LLFastTimerView::updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, U32& bar_index)
|
||||
{
|
||||
LLFastTimer _(FTM_UPDATE_TIMER_BAR_WIDTHS);
|
||||
const LLUnit<F32, LLUnits::Seconds> self_time = history_index == -1
|
||||
? mRecording.getPeriodMean(time_block->selfTime())
|
||||
? mRecording.getPeriodMean(time_block->selfTime(), RUNNING_AVERAGE_WIDTH)
|
||||
: mRecording.getPrevRecording(history_index).getSum(time_block->selfTime());
|
||||
|
||||
LLUnit<F32, LLUnits::Seconds> full_time = self_time;
|
||||
|
||||
// reserve a spot for this bar to be rendered before its children
|
||||
// even though we don't know its size yet
|
||||
std::vector<TimerBar>& bars = row.mBars;
|
||||
S32 bar_index = bars.size();
|
||||
bars.push_back(TimerBar());
|
||||
TimerBar& timer_bar = row.mBars[bar_index];
|
||||
bar_index++;
|
||||
|
||||
const bool children_visible = visible && !time_block->getCollapsed();
|
||||
for (TimeBlock::child_iter it = time_block->beginChildren(), end_it = time_block->endChildren(); it != end_it; ++it)
|
||||
{
|
||||
full_time += updateTimerBarWidths(*it, row, history_index, children_visible);
|
||||
full_time += updateTimerBarWidths(*it, row, history_index, bar_index);
|
||||
}
|
||||
|
||||
TimerBar& timer_bar = bars[bar_index];
|
||||
timer_bar.mTotalTime = full_time;
|
||||
timer_bar.mSelfTime = self_time;
|
||||
timer_bar.mTimeBlock = time_block;
|
||||
timer_bar.mVisible = visible;
|
||||
|
||||
return full_time;
|
||||
}
|
||||
|
|
@ -1528,22 +1543,17 @@ S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::TimeBlock* time_block, Timer
|
|||
{
|
||||
LLFastTimer _(FTM_UPDATE_TIMER_BAR_FRACTIONS);
|
||||
|
||||
std::vector<TimerBar>& bars = row.mBars;
|
||||
llassert(timer_bar_index < bars.size());
|
||||
TimerBar& timer_bar = bars[timer_bar_index];
|
||||
const LLUnit<F32, LLUnits::Seconds> child_time_width = timer_bar.mTotalTime - timer_bar.mSelfTime;
|
||||
timer_bar.mChildrenStart = timer_bar.mSelfStart;
|
||||
|
||||
if (mDisplayCenter == ALIGN_CENTER)
|
||||
{
|
||||
timer_bar.mChildrenStart += timer_bar.mSelfTime / 2;
|
||||
}
|
||||
else if (mDisplayCenter == ALIGN_RIGHT)
|
||||
{
|
||||
timer_bar.mChildrenStart += timer_bar.mSelfTime;
|
||||
}
|
||||
TimerBar& timer_bar = row.mBars[timer_bar_index];
|
||||
const LLUnit<F32, LLUnits::Seconds> bar_time = timer_bar.mTotalTime - timer_bar.mSelfTime;
|
||||
timer_bar.mChildrenStart = timer_bar.mSelfStart + timer_bar.mSelfTime / 2;
|
||||
timer_bar.mChildrenEnd = timer_bar.mChildrenStart + timer_bar.mTotalTime - timer_bar.mSelfTime;
|
||||
|
||||
if (timer_bar_index == 0)
|
||||
{
|
||||
timer_bar.mSelfStart = 0.f;
|
||||
timer_bar.mSelfEnd = bar_time;
|
||||
}
|
||||
|
||||
//now loop through children and figure out portion of bar image covered by each bar, now that we know the
|
||||
//sum of all children
|
||||
F32 bar_fraction_start = 0.f;
|
||||
|
|
@ -1556,8 +1566,7 @@ S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::TimeBlock* time_block, Timer
|
|||
{
|
||||
timer_bar_index++;
|
||||
|
||||
llassert(timer_bar_index < bars.size());
|
||||
TimerBar& child_timer_bar = bars[timer_bar_index];
|
||||
TimerBar& child_timer_bar = row.mBars[timer_bar_index];
|
||||
TimeBlock* child_time_block = *it;
|
||||
|
||||
if (last_child_timer_bar)
|
||||
|
|
@ -1574,15 +1583,15 @@ S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::TimeBlock* time_block, Timer
|
|||
}
|
||||
|
||||
child_timer_bar.mStartFraction = bar_fraction_start;
|
||||
child_timer_bar.mEndFraction = child_time_width > 0
|
||||
? bar_fraction_start + child_timer_bar.mTotalTime / child_time_width
|
||||
child_timer_bar.mEndFraction = bar_time > 0
|
||||
? bar_fraction_start + child_timer_bar.mTotalTime / bar_time
|
||||
: 1.f;
|
||||
child_timer_bar.mSelfStart = timer_bar.mChildrenStart
|
||||
+ child_timer_bar.mStartFraction
|
||||
* (timer_bar.mChildrenEnd - timer_bar.mChildrenStart);
|
||||
child_timer_bar.mSelfEnd = timer_bar.mChildrenStart
|
||||
+ child_timer_bar.mEndFraction
|
||||
* (timer_bar.mChildrenEnd - timer_bar.mChildrenStart);
|
||||
child_timer_bar.mSelfStart = timer_bar.mChildrenStart
|
||||
+ child_timer_bar.mStartFraction
|
||||
* (timer_bar.mChildrenEnd - timer_bar.mChildrenStart);
|
||||
child_timer_bar.mSelfEnd = timer_bar.mChildrenStart
|
||||
+ child_timer_bar.mEndFraction
|
||||
* (timer_bar.mChildrenEnd - timer_bar.mChildrenStart);
|
||||
|
||||
timer_bar_index = updateTimerBarOffsets(child_time_block, row, timer_bar_index);
|
||||
|
||||
|
|
@ -1591,16 +1600,15 @@ S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::TimeBlock* time_block, Timer
|
|||
return timer_bar_index;
|
||||
}
|
||||
|
||||
S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, S32 bar_index)
|
||||
S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, bool visible, S32 bar_index)
|
||||
{
|
||||
llassert(bar_index < row.mBars.size());
|
||||
TimerBar& timer_bar = row.mBars[bar_index];
|
||||
LLTrace::TimeBlock* time_block = timer_bar.mTimeBlock;
|
||||
|
||||
hovered |= mHoverID == time_block;
|
||||
|
||||
// animate scale of bar when hovering over that particular timer
|
||||
if ((F32)bar_rect.getWidth() * (timer_bar.mEndFraction - timer_bar.mStartFraction) > 2.f)
|
||||
if (visible && (F32)bar_rect.getWidth() * (timer_bar.mEndFraction - timer_bar.mStartFraction) > 2.f)
|
||||
{
|
||||
LLRect render_rect(bar_rect);
|
||||
S32 scale_offset = 0;
|
||||
|
|
@ -1637,15 +1645,17 @@ S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width,
|
|||
children_rect.mBottom = bar_rect.mBottom;
|
||||
}
|
||||
|
||||
bool children_visible = visible && !time_block->getCollapsed();
|
||||
|
||||
bar_index++;
|
||||
const U32 num_bars = row.mBars.size();
|
||||
const U32 num_bars = LLInstanceTracker<LLTrace::TimeBlock>::instanceCount();
|
||||
if (bar_index < num_bars && row.mBars[bar_index].mFirstChild)
|
||||
{
|
||||
bool is_last = false;
|
||||
do
|
||||
{
|
||||
is_last = row.mBars[bar_index].mLastChild;
|
||||
bar_index = drawBar(children_rect, row, image_width, image_height, hovered, bar_index);
|
||||
bar_index = drawBar(children_rect, row, image_width, image_height, hovered, children_visible, bar_index);
|
||||
}
|
||||
while(!is_last && bar_index < num_bars);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ private:
|
|||
virtual void onClickCloseBtn();
|
||||
void drawTicks();
|
||||
void drawLineGraph();
|
||||
void drawLegend(S32 y);
|
||||
S32 drawHelp(S32 y);
|
||||
void drawLegend();
|
||||
void drawHelp(S32 y);
|
||||
void drawBorders( S32 y, const S32 x_start, S32 barh, S32 dy);
|
||||
void drawBars();
|
||||
|
||||
|
|
@ -82,7 +82,6 @@ private:
|
|||
TimerBar()
|
||||
: mTotalTime(0),
|
||||
mSelfTime(0),
|
||||
mVisible(true),
|
||||
mStartFraction(0.f),
|
||||
mEndFraction(1.f),
|
||||
mFirstChild(false),
|
||||
|
|
@ -104,29 +103,26 @@ private:
|
|||
|
||||
struct TimerBarRow
|
||||
{
|
||||
S32 mBottom,
|
||||
mTop;
|
||||
std::vector<TimerBar> mBars;
|
||||
S32 mBottom,
|
||||
mTop;
|
||||
TimerBar* mBars;
|
||||
};
|
||||
|
||||
LLUnit<F32, LLUnits::Seconds> updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, bool visible = true);
|
||||
LLUnit<F32, LLUnits::Seconds> updateTimerBarWidths(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 history_index, U32& bar_index);
|
||||
S32 updateTimerBarOffsets(LLTrace::TimeBlock* time_block, TimerBarRow& row, S32 timer_bar_index = 0);
|
||||
S32 drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered = false, S32 bar_index = 0);
|
||||
S32 drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered = false, bool visible = true, S32 bar_index = 0);
|
||||
void setPauseState(bool pause_state);
|
||||
|
||||
std::deque<TimerBarRow> mTimerBarRows;
|
||||
TimerBarRow mAverageTimerRow;
|
||||
|
||||
enum ChildAlignment
|
||||
enum EDisplayType
|
||||
{
|
||||
ALIGN_LEFT,
|
||||
ALIGN_CENTER,
|
||||
ALIGN_RIGHT,
|
||||
ALIGN_COUNT
|
||||
} mDisplayCenter;
|
||||
bool mDisplayCalls,
|
||||
mDisplayHz,
|
||||
mPauseHistory;
|
||||
TIME,
|
||||
CALLS,
|
||||
HZ
|
||||
} mDisplayType;
|
||||
bool mPauseHistory;
|
||||
LLUnit<F64, LLUnits::Seconds> mAllTimeMax,
|
||||
mTotalTimeDisplay;
|
||||
S32 mScrollIndex,
|
||||
|
|
@ -137,7 +133,8 @@ private:
|
|||
LLTrace::TimeBlock* mHoverTimer;
|
||||
LLRect mToolTipRect,
|
||||
mGraphRect,
|
||||
mBarRect;
|
||||
mBarRect,
|
||||
mLegendRect;
|
||||
LLFrameTimer mHighlightTimer;
|
||||
LLTrace::PeriodicRecording mRecording;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,6 +16,27 @@
|
|||
width="700">
|
||||
<string name="pause" >Pause</string>
|
||||
<string name="run">Run</string>
|
||||
<combo_box name="time_scale_combo"
|
||||
follows="left|top"
|
||||
left="10"
|
||||
top="5"
|
||||
width="150"
|
||||
height="20">
|
||||
<item label="2x Average"/>
|
||||
<item label="Max"/>
|
||||
<item label="Recent Max"/>
|
||||
<item label="100ms"/>
|
||||
</combo_box>
|
||||
<combo_box name="metric_combo"
|
||||
follows="left|top"
|
||||
left_pad="10"
|
||||
top="5"
|
||||
width="150"
|
||||
height="20">
|
||||
<item label="Time"/>
|
||||
<item label="Number of Calls"/>
|
||||
<item label="Hz"/>
|
||||
</combo_box>
|
||||
<button follows="top|right"
|
||||
name="pause_btn"
|
||||
left="-200"
|
||||
|
|
@ -24,4 +45,52 @@
|
|||
height="40"
|
||||
label="Pause"
|
||||
font="SansSerifHuge"/>
|
||||
<layout_stack name="legend_stack"
|
||||
orientation="horizontal"
|
||||
left="0"
|
||||
top="50"
|
||||
right="695"
|
||||
bottom="500"
|
||||
follows="all">
|
||||
<layout_panel name="legend_panel"
|
||||
auto_resize="false"
|
||||
user_resize="true"
|
||||
width="220"
|
||||
height="450"
|
||||
min_width="100">
|
||||
<panel top="0"
|
||||
left="0"
|
||||
width="220"
|
||||
height="440"
|
||||
name="legend"
|
||||
follows="all"/>
|
||||
</layout_panel>
|
||||
<layout_panel name="timers_panel"
|
||||
auto_resize="true"
|
||||
user_resize="true"
|
||||
height="450"
|
||||
width="475"
|
||||
min_width="100">
|
||||
<layout_stack name="timer_bars_stack"
|
||||
orientation="vertical"
|
||||
left="0"
|
||||
top="0"
|
||||
width="475"
|
||||
height="445"
|
||||
follows="all">
|
||||
<layout_panel name="bars_panel"
|
||||
auto_resize="true"
|
||||
user_resize="true"
|
||||
top="0"
|
||||
width="475"
|
||||
height="210"/>
|
||||
<layout_panel name="lines_panel"
|
||||
auto_resize="false"
|
||||
user_resize="true"
|
||||
width="475"
|
||||
min_height="50"
|
||||
height="240"/>
|
||||
</layout_stack>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</floater>
|
||||
|
|
|
|||
Loading…
Reference in New Issue