summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorRichard Linden <none@none>2013-01-03 00:30:54 -0800
committerRichard Linden <none@none>2013-01-03 00:30:54 -0800
commitcda2cdda511eb2f7a58e284db2c852fd4a3808ae (patch)
tree0dcca3e19c051c827df5c167894f927b2692fe9c /indra/llcommon
parent3fd640a6e3dea7a3551c239323d782fb082e1dbd (diff)
SH-3406 WIP convert fast timers to lltrace system
made fast timer stack thread local added LLThreadLocalSingleton made LLThreadLocalPointer obey pointer rules for const added LLThreadLocalSingletonPointer for fast thread local pointers
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt1
-rw-r--r--indra/llcommon/llapr.cpp2
-rw-r--r--indra/llcommon/llfasttimer.cpp41
-rw-r--r--indra/llcommon/llfasttimer.h45
-rw-r--r--indra/llcommon/llsingleton.h52
-rw-r--r--indra/llcommon/llthreadlocalpointer.h164
-rw-r--r--indra/llcommon/llthreadlocalstorage.h254
-rw-r--r--indra/llcommon/lltrace.cpp13
-rw-r--r--indra/llcommon/lltrace.h32
-rw-r--r--indra/llcommon/lltracethreadrecorder.cpp33
-rw-r--r--indra/llcommon/lltracethreadrecorder.h9
11 files changed, 380 insertions, 266 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 5b76703af7..6f5fe1832a 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -242,6 +242,7 @@ set(llcommon_HEADER_FILES
llstringtable.h
llsys.h
llthread.h
+ llthreadlocalstorage.h
llthreadsafequeue.h
lltimer.h
lltrace.h
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 092c276936..d911f258b6 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -29,7 +29,7 @@
#include "linden_common.h"
#include "llapr.h"
#include "apr_dso.h"
-#include "llthreadlocalpointer.h"
+#include "llthreadlocalstorage.h"
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 7c90b946af..ad8cf7296e 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -70,8 +70,6 @@ U64 TimeBlock::sClockResolution = 1000000000; // Nanosecond resolution
U64 TimeBlock::sClockResolution = 1000000; // Microsecond resolution
#endif
-LLThreadLocalPointer<CurTimerData> TimeBlock::sCurTimerData;
-
static LLMutex* sLogLock = NULL;
static std::queue<LLSD> sLogQueue;
@@ -118,7 +116,7 @@ struct SortTimerByName
}
};
-TimeBlock& TimeBlock::getRootTimer()
+TimeBlock& TimeBlock::getRootTimeBlock()
{
static TimeBlock root_timer("root", true, NULL);
return root_timer;
@@ -185,7 +183,7 @@ void TimeBlock::processTimes()
{
get_clock_count(); // good place to calculate clock frequency
U64 cur_time = getCPUClockCount64();
- CurTimerData* cur_data = sCurTimerData.get();
+ BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();
// set up initial tree
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
@@ -193,11 +191,11 @@ void TimeBlock::processTimes()
++it)
{
TimeBlock& timer = *it;
- if (&timer == &TimeBlock::getRootTimer()) continue;
+ 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::getRootTimer())
+ if (timer.getParent() == &TimeBlock::getRootTimeBlock())
{
TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
@@ -214,20 +212,21 @@ void TimeBlock::processTimes()
// 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
- for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimer());
+ for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimeBlock());
it != end_timer_tree_bottom_up();
++it)
{
TimeBlock* timerp = *it;
// sort timers by time last called, so call graph makes sense
- if (timerp->getTreeNode().mNeedsSorting)
+ TimeBlockTreeNode& tree_node = timerp->getTreeNode();
+ if (tree_node.mNeedsSorting)
{
- std::sort(timerp->beginChildren(), timerp->endChildren(), SortTimerByName());
+ std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName());
}
// skip root timer
- if (timerp != &TimeBlock::getRootTimer())
+ if (timerp != &TimeBlock::getRootTimeBlock())
{
TimeBlockAccumulator* accumulator = timerp->getPrimaryAccumulator();
@@ -250,27 +249,27 @@ void TimeBlock::processTimes()
}
// walk up stack of active timers and accumulate current time while leaving timing structures active
- BlockTimer* cur_timer = cur_data->mCurTimer;
- TimeBlockAccumulator* accumulator = cur_data->mTimerData->getPrimaryAccumulator();
+ BlockTimer* cur_timer = stack_record->mActiveTimer;
+ TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
// root defined by parent pointing to self
- while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer)
+ while(cur_timer && cur_timer->mLastTimerData.mActiveTimer != cur_timer)
{
U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
- U64 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
- cur_data->mChildTime = 0;
+ U64 self_time_delta = cumulative_time_delta - stack_record->mChildTime;
+ stack_record->mChildTime = 0;
accumulator->mSelfTimeCounter += self_time_delta;
accumulator->mTotalTimeCounter += cumulative_time_delta;
cur_timer->mStartTime = cur_time;
- cur_data = &cur_timer->mLastTimerData;
- cur_data->mChildTime += cumulative_time_delta;
- if (cur_data->mTimerData)
+ stack_record = &cur_timer->mLastTimerData;
+ stack_record->mChildTime += cumulative_time_delta;
+ if (stack_record->mTimeBlock)
{
- accumulator = cur_data->mTimerData->getPrimaryAccumulator();
+ accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
}
- cur_timer = cur_timer->mLastTimerData.mCurTimer;
+ cur_timer = cur_timer->mLastTimerData.mActiveTimer;
}
@@ -374,7 +373,7 @@ void TimeBlock::dumpCurTimes()
LLTrace::Recording& last_frame_recording = frame_recording.getLastRecordingPeriod();
// walk over timers in depth order and output timings
- for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimer());
+ for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimeBlock());
it != end_timer_tree();
++it)
{
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 4d820d0664..995eebd16a 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -38,13 +38,29 @@ class LLMutex;
namespace LLTrace
{
-struct CurTimerData
+struct BlockTimerStackRecord
{
- class BlockTimer* mCurTimer;
- class TimeBlock* mTimerData;
+ class BlockTimer* mActiveTimer;
+ class TimeBlock* mTimeBlock;
U64 mChildTime;
};
+class ThreadTimerStack
+: public BlockTimerStackRecord,
+ public LLThreadLocalSingleton<ThreadTimerStack>
+{
+ friend LLThreadLocalSingleton<ThreadTimerStack>;
+ ThreadTimerStack()
+ {}
+
+public:
+ ThreadTimerStack& operator=(const BlockTimerStackRecord& other)
+ {
+ BlockTimerStackRecord::operator=(other);
+ return *this;
+ }
+};
+
class BlockTimer
{
public:
@@ -58,7 +74,7 @@ public:
private:
U64 mStartTime;
- CurTimerData mLastTimerData;
+ BlockTimerStackRecord mLastTimerData;
};
// stores a "named" timer instance to be reused via multiple BlockTimer stack instances
@@ -67,7 +83,7 @@ class TimeBlock
public LLInstanceTracker<TimeBlock>
{
public:
- TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimer());
+ TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimeBlock());
TimeBlockTreeNode& getTreeNode() const;
TimeBlock* getParent() const { return getTreeNode().getParent(); }
@@ -92,7 +108,7 @@ public:
return static_cast<TraceType<TimeBlockAccumulator::SelfTimeAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
}
- static TimeBlock& getRootTimer();
+ static TimeBlock& getRootTimeBlock();
static void pushLog(LLSD sd);
static void setLogLock(LLMutex* mutex);
static void writeLog(std::ostream& os);
@@ -252,7 +268,6 @@ public:
static std::string sLogName;
static bool sMetricLog,
sLog;
- static LLThreadLocalPointer<CurTimerData> sCurTimerData;
static U64 sClockResolution;
};
@@ -261,8 +276,8 @@ LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)
#if FAST_TIMER_ON
mStartTime = TimeBlock::getCPUClockCount64();
- CurTimerData* cur_timer_data = TimeBlock::sCurTimerData.get();
- TimeBlockAccumulator* accumulator = cur_timer_data->mTimerData->getPrimaryAccumulator();
+ BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
+ TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();
accumulator->mActiveCount++;
// keep current parent as long as it is active when we are
accumulator->mMoveUpTree |= (accumulator->mParent->getPrimaryAccumulator()->mActiveCount == 0);
@@ -270,8 +285,8 @@ LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)
// store top of stack
mLastTimerData = *cur_timer_data;
// push new information
- cur_timer_data->mCurTimer = this;
- cur_timer_data->mTimerData = &timer;
+ cur_timer_data->mActiveTimer = this;
+ cur_timer_data->mTimeBlock = &timer;
cur_timer_data->mChildTime = 0;
#endif
}
@@ -280,8 +295,8 @@ LL_FORCE_INLINE BlockTimer::~BlockTimer()
{
#if FAST_TIMER_ON
U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
- CurTimerData* cur_timer_data = TimeBlock::sCurTimerData.get();
- TimeBlockAccumulator* accumulator = cur_timer_data->mTimerData->getPrimaryAccumulator();
+ BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
+ TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();
accumulator->mCalls++;
accumulator->mSelfTimeCounter += total_time - cur_timer_data->mChildTime;
@@ -290,12 +305,12 @@ LL_FORCE_INLINE BlockTimer::~BlockTimer()
// store last caller to bootstrap tree creation
// do this in the destructor in case of recursion to get topmost caller
- accumulator->mLastCaller = mLastTimerData.mTimerData;
+ accumulator->mLastCaller = mLastTimerData.mTimeBlock;
// we are only tracking self time, so subtract our total time delta from parents
mLastTimerData.mChildTime += total_time;
- *TimeBlock::sCurTimerData = mLastTimerData;
+ *ThreadTimerStack::getIfExists() = mLastTimerData;
#endif
}
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 49d99f2cd0..f6b0a7194b 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -90,7 +90,7 @@ template <typename DERIVED_TYPE>
class LLSingleton : private boost::noncopyable
{
-private:
+protected:
typedef enum e_init_state
{
UNINITIALIZED,
@@ -124,7 +124,7 @@ private:
public:
virtual ~LLSingleton()
{
- SingletonInstanceData& data = getData();
+ SingletonInstanceData& data = getSingletonData();
data.mSingletonInstance = NULL;
data.mInitState = DELETED;
}
@@ -151,29 +151,15 @@ public:
*/
static void deleteSingleton()
{
- delete getData().mSingletonInstance;
- getData().mSingletonInstance = NULL;
- getData().mInitState = DELETED;
- }
-
- static SingletonInstanceData& getData()
- {
- // this is static to cache the lookup results
- static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
-
- // *TODO - look into making this threadsafe
- if(NULL == registry)
- {
- static SingletonInstanceData data;
- registry = &data;
- }
-
- return *static_cast<SingletonInstanceData *>(registry);
+ SingletonInstanceData& data = getSingletonData();
+ delete data.mSingletonInstance;
+ data.mSingletonInstance = NULL;
+ data.mInitState = DELETED;
}
static DERIVED_TYPE* getInstance()
{
- SingletonInstanceData& data = getData();
+ SingletonInstanceData& data = getSingletonData();
if (data.mInitState == CONSTRUCTING)
{
@@ -197,6 +183,12 @@ public:
return data.mSingletonInstance;
}
+ static DERIVED_TYPE* getIfExists()
+ {
+ SingletonInstanceData& data = getSingletonData();
+ return data.mSingletonInstance;
+ }
+
// Reference version of getInstance()
// Preferred over getInstance() as it disallows checking for NULL
static DERIVED_TYPE& instance()
@@ -208,17 +200,31 @@ public:
// Use this to avoid accessing singletons before the can safely be constructed
static bool instanceExists()
{
- return getData().mInitState == INITIALIZED;
+ return getSingletonData().mInitState == INITIALIZED;
}
// Has this singleton already been deleted?
// Use this to avoid accessing singletons from a static object's destructor
static bool destroyed()
{
- return getData().mInitState == DELETED;
+ return getSingletonData().mInitState == DELETED;
}
private:
+ static SingletonInstanceData& getSingletonData()
+ {
+ // this is static to cache the lookup results
+ static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
+
+ // *TODO - look into making this threadsafe
+ if(NULL == registry)
+ {
+ static SingletonInstanceData data;
+ registry = &data;
+ }
+
+ return *static_cast<SingletonInstanceData *>(registry);
+ }
virtual void initSingleton() {}
};
diff --git a/indra/llcommon/llthreadlocalpointer.h b/indra/llcommon/llthreadlocalpointer.h
deleted file mode 100644
index d40a8b5a27..0000000000
--- a/indra/llcommon/llthreadlocalpointer.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * @file llthreadlocalpointer.h
- * @author Richard
- * @brief Pointer class that manages a distinct value per thread
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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_LLTHREADLOCALPOINTER_H
-#define LL_LLTHREADLOCALPOINTER_H
-
-#include "llinstancetracker.h"
-#include "llapr.h"
-
-class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase>
-{
-public:
- LLThreadLocalPointerBase()
- : mThreadKey(NULL)
- {
- if (sInitialized)
- {
- initStorage();
- }
- }
-
- LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other)
- : mThreadKey(NULL)
- {
- if (sInitialized)
- {
- initStorage();
- }
- }
-
- ~LLThreadLocalPointerBase()
- {
- destroyStorage();
- }
-
- static void initAllThreadLocalStorage();
- static void destroyAllThreadLocalStorage();
-
-protected:
- void set(void* value);
-
- LL_FORCE_INLINE void* get()
- {
- // llassert(sInitialized);
- void* ptr;
- apr_status_t result =
- apr_threadkey_private_get(&ptr, mThreadKey);
- if (result != APR_SUCCESS)
- {
- ll_apr_warn_status(result);
- llerrs << "Failed to get thread local data" << llendl;
- }
- return ptr;
- }
-
- LL_FORCE_INLINE const void* get() const
- {
- void* ptr;
- apr_status_t result =
- apr_threadkey_private_get(&ptr, mThreadKey);
- if (result != APR_SUCCESS)
- {
- ll_apr_warn_status(result);
- llerrs << "Failed to get thread local data" << llendl;
- }
- return ptr;
- }
-
- void initStorage();
- void destroyStorage();
-
-protected:
- apr_threadkey_t* mThreadKey;
- static bool sInitialized;
-};
-
-template <typename T>
-class LLThreadLocalPointer : public LLThreadLocalPointerBase
-{
-public:
-
- LLThreadLocalPointer()
- {}
-
- explicit LLThreadLocalPointer(T* value)
- {
- set(value);
- }
-
-
- LLThreadLocalPointer(const LLThreadLocalPointer<T>& other)
- : LLThreadLocalPointerBase(other)
- {
- set(other.get());
- }
-
- LL_FORCE_INLINE T* get()
- {
- return (T*)LLThreadLocalPointerBase::get();
- }
-
- const T* get() const
- {
- return (const T*)LLThreadLocalPointerBase::get();
- }
-
- T* operator -> ()
- {
- return (T*)get();
- }
-
- const T* operator -> () const
- {
- return (T*)get();
- }
-
- T& operator*()
- {
- return *(T*)get();
- }
-
- const T& operator*() const
- {
- return *(T*)get();
- }
-
- LLThreadLocalPointer<T>& operator = (T* value)
- {
- set((void*)value);
- return *this;
- }
-
- bool operator ==(T* other)
- {
- if (!sInitialized) return false;
- return get() == other;
- }
-};
-
-#endif // LL_LLTHREADLOCALPOINTER_H
diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h
new file mode 100644
index 0000000000..fdf0c18085
--- /dev/null
+++ b/indra/llcommon/llthreadlocalstorage.h
@@ -0,0 +1,254 @@
+/**
+ * @file llthreadlocalstorage.h
+ * @author Richard
+ * @brief Class wrappers for thread local storage
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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_LLTHREADLOCALSTORAGE_H
+#define LL_LLTHREADLOCALSTORAGE_H
+
+#include "llinstancetracker.h"
+#include "llapr.h"
+
+class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase>
+{
+public:
+ LLThreadLocalPointerBase()
+ : mThreadKey(NULL)
+ {
+ if (sInitialized)
+ {
+ initStorage();
+ }
+ }
+
+ LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other)
+ : mThreadKey(NULL)
+ {
+ if (sInitialized)
+ {
+ initStorage();
+ }
+ }
+
+ ~LLThreadLocalPointerBase()
+ {
+ destroyStorage();
+ }
+
+ static void initAllThreadLocalStorage();
+ static void destroyAllThreadLocalStorage();
+
+protected:
+ void set(void* value);
+
+ LL_FORCE_INLINE void* get() const
+ {
+ // llassert(sInitialized);
+ void* ptr;
+ apr_status_t result =
+ apr_threadkey_private_get(&ptr, mThreadKey);
+ if (result != APR_SUCCESS)
+ {
+ ll_apr_warn_status(result);
+ llerrs << "Failed to get thread local data" << llendl;
+ }
+ return ptr;
+ }
+
+ void initStorage();
+ void destroyStorage();
+
+protected:
+ apr_threadkey_t* mThreadKey;
+ static bool sInitialized;
+};
+
+template <typename T>
+class LLThreadLocalPointer : public LLThreadLocalPointerBase
+{
+public:
+
+ LLThreadLocalPointer()
+ {}
+
+ explicit LLThreadLocalPointer(T* value)
+ {
+ set(value);
+ }
+
+
+ LLThreadLocalPointer(const LLThreadLocalPointer<T>& other)
+ : LLThreadLocalPointerBase(other)
+ {
+ set(other.get());
+ }
+
+ LL_FORCE_INLINE T* get() const
+ {
+ return (T*)LLThreadLocalPointerBase::get();
+ }
+
+ T* operator -> () const
+ {
+ return (T*)get();
+ }
+
+ T& operator*() const
+ {
+ return *(T*)get();
+ }
+
+ LLThreadLocalPointer<T>& operator = (T* value)
+ {
+ set((void*)value);
+ return *this;
+ }
+
+ bool operator ==(const T* other) const
+ {
+ if (!sInitialized) return false;
+ return get() == other;
+ }
+};
+
+template<typename DERIVED_TYPE>
+class LLThreadLocalSingleton
+{
+ typedef enum e_init_state
+ {
+ UNINITIALIZED = 0,
+ CONSTRUCTING,
+ INITIALIZING,
+ INITIALIZED,
+ DELETED
+ } EInitState;
+
+public:
+ LLThreadLocalSingleton()
+ {}
+
+ virtual ~LLThreadLocalSingleton()
+ {
+ sInstance = NULL;
+ sInitState = DELETED;
+ }
+
+ static void deleteSingleton()
+ {
+ delete sInstance;
+ sInstance = NULL;
+ sInitState = DELETED;
+ }
+
+ static DERIVED_TYPE* getInstance()
+ {
+ if (sInitState == CONSTRUCTING)
+ {
+ llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
+ }
+
+ if (sInitState == DELETED)
+ {
+ llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
+ }
+
+ if (!sInstance)
+ {
+ sInitState = CONSTRUCTING;
+ sInstance = new DERIVED_TYPE();
+ sInitState = INITIALIZING;
+ sInstance->initSingleton();
+ sInitState = INITIALIZED;
+ }
+
+ return sInstance;
+ }
+
+ static DERIVED_TYPE* getIfExists()
+ {
+ return sInstance;
+ }
+
+ // Reference version of getInstance()
+ // Preferred over getInstance() as it disallows checking for NULL
+ static DERIVED_TYPE& instance()
+ {
+ return *getInstance();
+ }
+
+ // Has this singleton been created uet?
+ // Use this to avoid accessing singletons before the can safely be constructed
+ static bool instanceExists()
+ {
+ return sInitState == INITIALIZED;
+ }
+
+ // Has this singleton already been deleted?
+ // Use this to avoid accessing singletons from a static object's destructor
+ static bool destroyed()
+ {
+ return sInitState == DELETED;
+ }
+private:
+ LLThreadLocalSingleton(const LLThreadLocalSingleton& other);
+ virtual void initSingleton() {}
+
+ static __declspec(thread) DERIVED_TYPE* sInstance;
+ static __declspec(thread) EInitState sInitState;
+};
+
+template<typename DERIVED_TYPE>
+__declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
+
+template<typename DERIVED_TYPE>
+__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
+
+template<typename DERIVED_TYPE>
+class LLThreadLocalSingletonPointer
+{
+public:
+ void operator =(DERIVED_TYPE* value)
+ {
+ sInstance = value;
+ }
+
+ LL_FORCE_INLINE static DERIVED_TYPE* getInstance()
+ {
+ return sInstance;
+ }
+
+ LL_FORCE_INLINE static void setInstance(DERIVED_TYPE* instance)
+ {
+ sInstance = instance;
+ }
+
+private:
+ static __declspec(thread) DERIVED_TYPE* sInstance;
+};
+
+template<typename DERIVED_TYPE>
+__declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL;
+
+#endif // LL_LLTHREADLOCALSTORAGE_H
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
index 9d0c93b352..9cadd70dd8 100644
--- a/indra/llcommon/lltrace.cpp
+++ b/indra/llcommon/lltrace.cpp
@@ -60,12 +60,23 @@ MasterThreadRecorder& getMasterThreadRecorder()
return *gMasterThreadRecorder;
}
-LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder()
+LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr()
{
static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder;
return s_thread_recorder;
}
+const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder()
+{
+ return get_thread_recorder_ptr();
+}
+
+void set_thread_recorder(ThreadRecorder* recorder)
+{
+ get_thread_recorder_ptr() = recorder;
+}
+
+
TimeBlockTreeNode::TimeBlockTreeNode()
: mBlock(NULL),
mParent(NULL),
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
index 05191cafaa..285d4389af 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -34,7 +34,7 @@
#include "llrefcount.h"
#include "llunit.h"
#include "llapr.h"
-#include "llthreadlocalpointer.h"
+#include "llthreadlocalstorage.h"
#include <list>
@@ -70,7 +70,8 @@ namespace LLTrace
void cleanup();
bool isInitialized();
- LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder();
+ const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder();
+ void set_thread_recorder(class ThreadRecorder*);
class MasterThreadRecorder& getMasterThreadRecorder();
@@ -106,9 +107,9 @@ namespace LLTrace
~AccumulatorBuffer()
{
- if (sPrimaryStorage == mStorage)
+ if (LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage)
{
- sPrimaryStorage = getDefaultBuffer()->mStorage;
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(getDefaultBuffer()->mStorage);
}
delete[] mStorage;
}
@@ -151,17 +152,17 @@ namespace LLTrace
void makePrimary()
{
- sPrimaryStorage = mStorage;
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage);
}
bool isPrimary() const
{
- return sPrimaryStorage == mStorage;
+ return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;
}
LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()
{
- return sPrimaryStorage.get();
+ return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();
}
// NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned
@@ -214,7 +215,6 @@ namespace LLTrace
{
// this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data
// so as not to trigger an access violation
- //TODO: make this thread local but need to either demand-init apr or remove apr dependency
static self_t* sBuffer = new AccumulatorBuffer(StaticAllocationMarker());
static bool sInitialized = false;
if (!sInitialized)
@@ -229,9 +229,7 @@ namespace LLTrace
ACCUMULATOR* mStorage;
size_t mStorageSize;
size_t mNextStorageSlot;
- static LLThreadLocalPointer<ACCUMULATOR> sPrimaryStorage;
};
- template<typename ACCUMULATOR> LLThreadLocalPointer<ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>::sPrimaryStorage;
//TODO: replace with decltype when C++11 is enabled
template<typename T>
@@ -250,10 +248,9 @@ namespace LLTrace
TraceType(const char* name, const char* description = NULL)
: LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>(name),
mName(name),
- mDescription(description ? description : "")
- {
- mAccumulatorIndex = AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot();
- }
+ mDescription(description ? description : ""),
+ mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot())
+ {}
LL_FORCE_INLINE ACCUMULATOR* getPrimaryAccumulator() const
{
@@ -263,13 +260,12 @@ namespace LLTrace
size_t getIndex() const { return mAccumulatorIndex; }
- std::string& getName() { return mName; }
const std::string& getName() const { return mName; }
protected:
- std::string mName;
- std::string mDescription;
- size_t mAccumulatorIndex;
+ const std::string mName;
+ const std::string mDescription;
+ const size_t mAccumulatorIndex;
};
template<typename T>
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
index 156b0ef26b..9fb789c62d 100644
--- a/indra/llcommon/lltracethreadrecorder.cpp
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -39,18 +39,17 @@ namespace LLTrace
ThreadRecorder::ThreadRecorder()
{
//NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies
- get_thread_recorder() = this;
+ set_thread_recorder(this);
+ TimeBlock& root_time_block = TimeBlock::getRootTimeBlock();
- mRootTimerData = new CurTimerData();
- mRootTimerData->mTimerData = &TimeBlock::getRootTimer();
- TimeBlock::sCurTimerData = mRootTimerData;
+ ThreadTimerStack* timer_stack = ThreadTimerStack::getInstance();
+ timer_stack->mTimeBlock = &root_time_block;
+ timer_stack->mActiveTimer = NULL;
mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size();
mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes];
- mFullRecording.start();
-
- TimeBlock& root_timer = TimeBlock::getRootTimer();
+ mThreadRecording.start();
// initialize time block parent pointers
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
@@ -60,15 +59,15 @@ ThreadRecorder::ThreadRecorder()
TimeBlock& time_block = *it;
TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()];
tree_node.mBlock = &time_block;
- tree_node.mParent = &root_timer;
+ tree_node.mParent = &root_time_block;
- it->getPrimaryAccumulator()->mParent = &root_timer;
+ it->getPrimaryAccumulator()->mParent = &root_time_block;
}
- mRootTimer = new BlockTimer(root_timer);
- mRootTimerData->mCurTimer = mRootTimer;
+ mRootTimer = new BlockTimer(root_time_block);
+ timer_stack->mActiveTimer = mRootTimer;
- TimeBlock::getRootTimer().getPrimaryAccumulator()->mActiveCount = 1;
+ TimeBlock::getRootTimeBlock().getPrimaryAccumulator()->mActiveCount = 1;
}
ThreadRecorder::~ThreadRecorder()
@@ -79,9 +78,7 @@ ThreadRecorder::~ThreadRecorder()
{
mActiveRecordings.front().mTargetRecording->stop();
}
- get_thread_recorder() = NULL;
- TimeBlock::sCurTimerData = NULL;
- delete mRootTimerData;
+ set_thread_recorder(NULL);
delete[] mTimeBlockTreeNodes;
}
@@ -196,12 +193,12 @@ SlaveThreadRecorder::~SlaveThreadRecorder()
void SlaveThreadRecorder::pushToMaster()
{
- mFullRecording.stop();
+ mThreadRecording.stop();
{
LLMutexLock(getMasterThreadRecorder().getSlaveListMutex());
- mSharedData.appendFrom(mFullRecording);
+ mSharedData.appendFrom(mThreadRecording);
}
- mFullRecording.start();
+ mThreadRecording.start();
}
void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source )
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
index d09527eced..337035974c 100644
--- a/indra/llcommon/lltracethreadrecorder.h
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -62,13 +62,12 @@ namespace LLTrace
void moveBaselineToTarget();
};
- Recording mFullRecording;
+ Recording mThreadRecording;
std::list<ActiveRecording> mActiveRecordings;
- struct CurTimerData* mRootTimerData;
- class BlockTimer* mRootTimer;
- TimeBlockTreeNode* mTimeBlockTreeNodes;
- size_t mNumTimeBlockTreeNodes;
+ class BlockTimer* mRootTimer;
+ TimeBlockTreeNode* mTimeBlockTreeNodes;
+ size_t mNumTimeBlockTreeNodes;
};
class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder