SH-3468 WIP add memory tracking base class

created memory tracking trace type
instrumented a few classes with memory tracking
master
Richard Linden 2012-12-18 00:58:26 -08:00
parent 8c2e3bea71
commit 1f56e57008
12 changed files with 344 additions and 45 deletions

View File

@ -424,9 +424,9 @@ namespace LLTrace
//
// members
//
U64 mSelfTimeCounter,
mTotalTimeCounter;
U32 mCalls;
U64 mSelfTimeCounter,
mTotalTimeCounter;
U32 mCalls;
};
@ -509,6 +509,268 @@ namespace LLTrace
trace_t::getPrimaryAccumulator().add(LLUnits::rawValue(converted_value));
}
};
}
struct MemStatAccumulator
{
MemStatAccumulator()
: mSize(0),
mChildSize(0),
mAllocatedCount(0),
mDeallocatedCount(0)
{}
void addSamples(const MemStatAccumulator& other)
{
mSize += other.mSize;
mChildSize += other.mChildSize;
mAllocatedCount += other.mAllocatedCount;
mDeallocatedCount += other.mDeallocatedCount;
}
void reset(const MemStatAccumulator* other)
{
mSize = 0;
mChildSize = 0;
mAllocatedCount = 0;
mDeallocatedCount = 0;
}
size_t mSize,
mChildSize;
int mAllocatedCount,
mDeallocatedCount;
};
class MemStat : public TraceType<MemStatAccumulator>
{
public:
typedef TraceType<MemStatAccumulator> trace_t;
MemStat(const char* name)
: trace_t(name)
{}
};
// measures effective memory footprint of specified type
// specialize to cover different types
template<typename T>
struct MemFootprint
{
static size_t measure(const T& value)
{
return sizeof(T);
}
static size_t measure()
{
return sizeof(T);
}
};
template<typename T>
struct MemFootprint<T*>
{
static size_t measure(const T* value)
{
if (!value)
{
return 0;
}
return MemFootprint<T>::measure(*value);
}
static size_t measure()
{
return MemFootPrint<T>::measure();
}
};
template<typename T>
struct MemFootprint<std::basic_string<T> >
{
static size_t measure(const std::basic_string<T>& value)
{
return value.capacity() * sizeof(T);
}
static size_t measure()
{
return sizeof(std::basic_string<T>);
}
};
template<typename T>
struct MemFootprint<std::vector<T> >
{
static size_t measure(const std::vector<T>& value)
{
return value.capacity() * MemFootPrint<T>::measure();
}
static size_t measure()
{
return sizeof(std::vector<T>);
}
};
template<typename T>
struct MemFootprint<std::list<T> >
{
static size_t measure(const std::list<T>& value)
{
return value.size() * (MemFootPrint<T>::measure() + sizeof(void*) * 2);
}
static size_t measure()
{
return sizeof(std::list<T>);
}
};
template<typename T>
class MemTrackable
{
template<typename TRACKED, typename TRACKED_IS_TRACKER>
struct TrackMemImpl;
typedef MemTrackable<T> mem_trackable_t;
public:
typedef void mem_trackable_tag_t;
~MemTrackable()
{
memDisclaim(mMemFootprint);
}
void* operator new(size_t allocation_size)
{
// reserve 8 bytes for allocation size (and preserving 8 byte alignment of structs)
void* allocation = ::operator new(allocation_size + 8);
*(size_t*)allocation = allocation_size;
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
accumulator.mSize += allocation_size;
accumulator.mAllocatedCount++;
return (void*)((char*)allocation + 8);
}
void operator delete(void* ptr)
{
size_t* allocation_size = (size_t*)((char*)ptr - 8);
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
accumulator.mSize -= *allocation_size;
accumulator.mAllocatedCount--;
accumulator.mDeallocatedCount++;
::delete((char*)ptr - 8);
}
void *operator new [](size_t size)
{
size_t* result = (size_t*)malloc(size + 8);
*result = size;
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
accumulator.mSize += size;
accumulator.mAllocatedCount++;
return (void*)((char*)result + 8);
}
void operator delete[](void* ptr)
{
size_t* allocation_size = (size_t*)((char*)ptr - 8);
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
accumulator.mSize -= *allocation_size;
accumulator.mAllocatedCount--;
accumulator.mDeallocatedCount++;
::delete[]((char*)ptr - 8);
}
// claim memory associated with other objects/data as our own, adding to our calculated footprint
template<typename T>
T& memClaim(T& value)
{
TrackMemImpl<T>::claim(*this, value);
return value;
}
template<typename T>
const T& memClaim(const T& value)
{
TrackMemImpl<T>::claim(*this, value);
return value;
}
void memClaim(size_t size)
{
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
mMemFootprint += size;
accumulator.mSize += size;
}
// remove memory we had claimed from our calculated footprint
template<typename T>
T& memDisclaim(T& value)
{
TrackMemImpl<T>::disclaim(*this, value);
return value;
}
template<typename T>
const T& memDisclaim(const T& value)
{
TrackMemImpl<T>::disclaim(*this, value);
return value;
}
void memDisclaim(size_t size)
{
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
accumulator.mSize -= size;
mMemFootprint -= size;
}
private:
size_t mMemFootprint;
template<typename TRACKED, typename TRACKED_IS_TRACKER = void>
struct TrackMemImpl
{
static void claim(mem_trackable_t& tracker, const TRACKED& tracked)
{
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
size_t footprint = MemFootprint<TRACKED>::measure(tracked);
accumulator.mSize += footprint;
tracker.mMemFootprint += footprint;
}
static void disclaim(mem_trackable_t& tracker, const TRACKED& tracked)
{
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
size_t footprint = MemFootprint<TRACKED>::measure(tracked);
accumulator.mSize -= footprint;
tracker.mMemFootprint -= footprint;
}
};
template<typename TRACKED>
struct TrackMemImpl<TRACKED, typename TRACKED::mem_trackable_tag_t>
{
static void claim(mem_trackable_t& tracker, TRACKED& tracked)
{
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
accumulator.mChildSize += MemFootprint<TRACKED>::measure(tracked);
}
static void disclaim(mem_trackable_t& tracker, TRACKED& tracked)
{
MemStatAccumulator& accumulator = sStat.getPrimaryAccumulator();
accumulator.mChildSize -= MemFootprint<TRACKED>::measure(tracked);
}
};
static MemStat sStat;
};
template<typename T> MemStat MemTrackable<T>::sStat(typeid(T).name());
}
#endif // LL_LLTRACE_H

View File

@ -157,7 +157,8 @@ void LLImageBase::sanityCheck()
// virtual
void LLImageBase::deleteData()
{
FREE_MEM(sPrivatePoolp, mData) ;
FREE_MEM(sPrivatePoolp, mData);
memDisclaim(mDataSize);
mData = NULL;
mDataSize = 0;
}
@ -201,6 +202,7 @@ U8* LLImageBase::allocateData(S32 size)
mBadBufferAllocation = true ;
}
mDataSize = size;
memClaim(mDataSize);
}
return mData;
@ -222,7 +224,9 @@ U8* LLImageBase::reallocateData(S32 size)
FREE_MEM(sPrivatePoolp, mData) ;
}
mData = new_datap;
memDisclaim(mDataSize);
mDataSize = size;
memClaim(mDataSize);
return mData;
}
@ -1584,7 +1588,9 @@ static void avg4_colors2(const U8* a, const U8* b, const U8* c, const U8* d, U8*
void LLImageBase::setDataAndSize(U8 *data, S32 size)
{
ll_assert_aligned(data, 16);
memDisclaim(mDataSize);
mData = data; mDataSize = size;
memClaim(mDataSize);
}
//static

View File

@ -30,6 +30,7 @@
#include "lluuid.h"
#include "llstring.h"
#include "llthread.h"
#include "lltrace.h"
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
@ -110,7 +111,9 @@ protected:
//============================================================================
// Image base class
class LLImageBase : public LLThreadSafeRefCount
class LLImageBase
: public LLThreadSafeRefCount,
public LLTrace::MemTrackable<LLImageBase>
{
protected:
virtual ~LLImageBase();

View File

@ -561,7 +561,7 @@ void LLTextBase::drawText()
if ( (mSpellCheckStart != start) || (mSpellCheckEnd != end) )
{
const LLWString& wstrText = getWText();
mMisspellRanges.clear();
memDisclaim(mMisspellRanges).clear();
segment_set_t::const_iterator seg_it = getSegIterContaining(start);
while (mSegments.end() != seg_it)
@ -632,6 +632,7 @@ void LLTextBase::drawText()
mSpellCheckStart = start;
mSpellCheckEnd = end;
memClaim(mMisspellRanges);
}
}
@ -890,10 +891,12 @@ void LLTextBase::createDefaultSegment()
// ensures that there is always at least one segment
if (mSegments.empty())
{
memDisclaim(mSegments);
LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
LLTextSegmentPtr default_segment = new LLNormalTextSegment( sp, 0, getLength() + 1, *this);
mSegments.insert(default_segment);
default_segment->linkToDocument(this);
memClaim(mSegments);
}
}
@ -904,6 +907,8 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert)
return;
}
memDisclaim(mSegments);
segment_set_t::iterator cur_seg_iter = getSegIterContaining(segment_to_insert->getStart());
S32 reflow_start_index = 0;
@ -976,6 +981,7 @@ void LLTextBase::insertSegment(LLTextSegmentPtr segment_to_insert)
// layout potentially changed
needsReflow(reflow_start_index);
memClaim(mSegments);
}
BOOL LLTextBase::handleMouseDown(S32 x, S32 y, MASK mask)
@ -1271,8 +1277,11 @@ void LLTextBase::replaceWithSuggestion(U32 index)
removeStringNoUndo(it->first, it->second - it->first);
// Insert the suggestion in its place
memDisclaim(mSuggestionList);
LLWString suggestion = utf8str_to_wstring(mSuggestionList[index]);
insertStringNoUndo(it->first, utf8str_to_wstring(mSuggestionList[index]));
memClaim(mSuggestionList);
setCursorPos(it->first + (S32)suggestion.length());
break;
@ -1334,7 +1343,7 @@ bool LLTextBase::isMisspelledWord(U32 pos) const
void LLTextBase::onSpellCheckSettingsChange()
{
// Recheck the spelling on every change
mMisspellRanges.clear();
memDisclaim(mMisspellRanges).clear();
mSpellCheckStart = mSpellCheckEnd = -1;
}
@ -1593,7 +1602,7 @@ LLRect LLTextBase::getTextBoundingRect()
void LLTextBase::clearSegments()
{
mSegments.clear();
memDisclaim(mSegments).clear();
createDefaultSegment();
}
@ -3057,7 +3066,9 @@ void LLNormalTextSegment::setToolTip(const std::string& tooltip)
llwarns << "LLTextSegment::setToolTip: cannot replace keyword tooltip." << llendl;
return;
}
memDisclaim(mTooltip);
mTooltip = tooltip;
memClaim(mTooltip);
}
bool LLNormalTextSegment::getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const

View File

@ -50,7 +50,10 @@ class LLUrlMatch;
/// includes a start/end offset from the start of the string, a
/// style to render with, an optional tooltip, etc.
///
class LLTextSegment : public LLRefCount, public LLMouseHandler
class LLTextSegment
: public LLRefCount,
public LLMouseHandler,
public LLTrace::MemTrackable<LLTextSegment>
{
public:
LLTextSegment(S32 start, S32 end) : mStart(start), mEnd(end){};

View File

@ -118,6 +118,7 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel)
mDoubleClickSignal(NULL),
mTransparencyType(TT_DEFAULT)
{
memClaim(viewmodel.get());
}
void LLUICtrl::initFromParams(const Params& p)
@ -940,7 +941,7 @@ boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (L
}
boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb )
{
if (!mValidateSignal) mValidateSignal = new enable_signal_t();
if (!mValidateSignal) mValidateSignal = memClaim(new enable_signal_t());
return mValidateSignal->connect(boost::bind(cb, _2));
}
@ -1003,55 +1004,55 @@ boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackPa
boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb )
{
if (!mCommitSignal) mCommitSignal = new commit_signal_t();
if (!mCommitSignal) mCommitSignal = memClaim(new commit_signal_t());
return mCommitSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb )
{
if (!mValidateSignal) mValidateSignal = new enable_signal_t();
if (!mValidateSignal) mValidateSignal = memClaim(new enable_signal_t());
return mValidateSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb )
{
if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t();
if (!mMouseEnterSignal) mMouseEnterSignal = memClaim(new commit_signal_t());
return mMouseEnterSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb )
{
if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t();
if (!mMouseLeaveSignal) mMouseLeaveSignal = memClaim(new commit_signal_t());
return mMouseLeaveSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb )
{
if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t();
if (!mMouseDownSignal) mMouseDownSignal = memClaim(new mouse_signal_t());
return mMouseDownSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb )
{
if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t();
if (!mMouseUpSignal) mMouseUpSignal = memClaim(new mouse_signal_t());
return mMouseUpSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb )
{
if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t();
if (!mRightMouseDownSignal) mRightMouseDownSignal = memClaim(new mouse_signal_t());
return mRightMouseDownSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb )
{
if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t();
if (!mRightMouseUpSignal) mRightMouseUpSignal = memClaim(new mouse_signal_t());
return mRightMouseUpSignal->connect(cb);
}
boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb )
{
if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t();
if (!mDoubleClickSignal) mDoubleClickSignal = memClaim(new mouse_signal_t());
return mDoubleClickSignal->connect(cb);
}

View File

@ -101,7 +101,8 @@ class LLView
: public LLMouseHandler, // handles mouse events
public LLFocusableElement, // handles keyboard events
public LLMortician, // lazy deletion
public LLHandleProvider<LLView> // passes out weak references to self
public LLHandleProvider<LLView>, // passes out weak references to self
public LLTrace::MemTrackable<LLView> // track memory usage
{
public:
struct Follows : public LLInitParam::ChoiceBlock<Follows>

View File

@ -80,7 +80,10 @@ LLTextViewModel::LLTextViewModel(const LLSD& value)
void LLTextViewModel::setValue(const LLSD& value)
{
LLViewModel::setValue(value);
memDisclaim(mDisplay);
mDisplay = utf8str_to_wstring(value.asString());
memClaim(mDisplay);
// mDisplay and mValue agree
mUpdateFromDisplay = false;
}
@ -91,7 +94,9 @@ void LLTextViewModel::setDisplay(const LLWString& value)
// and do the utf8str_to_wstring() to get the corresponding mDisplay
// value. But a text editor might want to edit the display string
// directly, then convert back to UTF8 on commit.
memDisclaim(mDisplay);
mDisplay = value;
memClaim(mDisplay);
mDirty = true;
// Don't immediately convert to UTF8 -- do it lazily -- we expect many
// more setDisplay() calls than getValue() calls. Just flag that it needs

View File

@ -60,7 +60,9 @@ typedef LLPointer<LLListViewModel> LLListViewModelPtr;
* LLViewModel data. This way, the LLViewModel is quietly deleted when the
* last referencing widget is destroyed.
*/
class LLViewModel: public LLRefCount
class LLViewModel
: public LLRefCount,
public LLTrace::MemTrackable<LLViewModel>
{
public:
LLViewModel();

View File

@ -59,7 +59,9 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;
// All data for new renderer goes into this class.
LL_ALIGN_PREFIX(16)
class LLDrawable : public LLRefCount
class LLDrawable
: public LLRefCount,
public LLTrace::MemTrackable<LLDrawable>
{
public:
LLDrawable(const LLDrawable& rhs)
@ -316,24 +318,23 @@ public:
private:
typedef std::vector<LLFace*> face_list_t;
U32 mState;
S32 mRenderType;
LLPointer<LLViewerObject> mVObjp;
face_list_t mFaces;
LLSpatialGroup* mSpatialGroupp;
LLPointer<LLDrawable> mSpatialBridge;
U32 mState;
S32 mRenderType;
LLPointer<LLViewerObject> mVObjp;
face_list_t mFaces;
LLSpatialGroup* mSpatialGroupp;
LLPointer<LLDrawable> mSpatialBridge;
mutable U32 mVisible;
F32 mRadius;
F32 mBinRadius;
mutable S32 mBinIndex;
S32 mGeneration;
LLVector3 mCurrentScale;
static U32 sCurVisible; // Counter for what value of mVisible means currently visible
mutable U32 mVisible;
F32 mRadius;
F32 mBinRadius;
mutable S32 mBinIndex;
S32 mGeneration;
static U32 sNumZombieDrawables;
LLVector3 mCurrentScale;
static U32 sCurVisible; // Counter for what value of mVisible means currently visible
static U32 sNumZombieDrawables;
static LLDynamicArrayPtr<LLPointer<LLDrawable> > sDeadList;
} LL_ALIGN_POSTFIX(16);

View File

@ -262,11 +262,11 @@ public:
LLVector2 mTexExtents[2];
F32 mDistance;
F32 mLastUpdateTime;
F32 mLastSkinTime;
F32 mLastMoveTime;
LLMatrix4* mTextureMatrix;
LLDrawInfo* mDrawInfo;
F32 mLastUpdateTime;
F32 mLastSkinTime;
F32 mLastMoveTime;
LLMatrix4* mTextureMatrix;
LLDrawInfo* mDrawInfo;
private:
LLPointer<LLVertexBuffer> mVertexBuffer;

View File

@ -107,7 +107,11 @@ struct PotentialReturnableObject
//============================================================================
class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
class LLViewerObject
: public LLPrimitive,
public LLRefCount,
public LLGLUpdate,
public LLTrace::MemTrackable<LLViewerObject>
{
protected:
~LLViewerObject(); // use unref()