diff options
author | Richard Linden <none@none> | 2012-12-18 00:58:26 -0800 |
---|---|---|
committer | Richard Linden <none@none> | 2012-12-18 00:58:26 -0800 |
commit | 1f56e57008f5a50c9e75fc0b4512c483ac359a52 (patch) | |
tree | 6631b12beaf3cf64e093730e9c93df34b883472c | |
parent | 8c2e3bea71ea15b805a9e2a288744f10d195d803 (diff) |
SH-3468 WIP add memory tracking base class
created memory tracking trace type
instrumented a few classes with memory tracking
-rw-r--r-- | indra/llcommon/lltrace.h | 270 | ||||
-rw-r--r-- | indra/llimage/llimage.cpp | 8 | ||||
-rw-r--r-- | indra/llimage/llimage.h | 5 | ||||
-rw-r--r-- | indra/llui/lltextbase.cpp | 17 | ||||
-rw-r--r-- | indra/llui/lltextbase.h | 5 | ||||
-rw-r--r-- | indra/llui/lluictrl.cpp | 21 | ||||
-rw-r--r-- | indra/llui/llview.h | 3 | ||||
-rw-r--r-- | indra/llui/llviewmodel.cpp | 5 | ||||
-rw-r--r-- | indra/llui/llviewmodel.h | 4 | ||||
-rw-r--r-- | indra/newview/lldrawable.h | 35 | ||||
-rw-r--r-- | indra/newview/llface.h | 10 | ||||
-rw-r--r-- | indra/newview/llviewerobject.h | 6 |
12 files changed, 344 insertions, 45 deletions
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index d29d43a92c..d4fc93342d 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -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 diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 914bf836c1..22dd809ef3 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -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 diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index b87ce6f060..d945d54404 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -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(); diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 3815eec447..31d67a9e08 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -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 diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 90b147cee1..966dd93888 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -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){}; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index b9c843e931..08358484ef 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -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); } diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 1c35349510..29ee2125f9 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -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> diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp index a9f8acc440..dff0dcb2fd 100644 --- a/indra/llui/llviewmodel.cpp +++ b/indra/llui/llviewmodel.cpp @@ -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 diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h index ef2e314799..cec0368460 100644 --- a/indra/llui/llviewmodel.h +++ b/indra/llui/llviewmodel.h @@ -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(); diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 4608d16fec..f15090fb87 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -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); diff --git a/indra/newview/llface.h b/indra/newview/llface.h index de4d03351c..15c9e7856f 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -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; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 97cf0a4850..14ea8ded38 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -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() |