summaryrefslogtreecommitdiff
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
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
-rw-r--r--indra/llaudio/llaudiodecodemgr.cpp1
-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
-rw-r--r--indra/llmessage/llbuffer.cpp1
-rw-r--r--indra/llmessage/lldispatcher.cpp1
14 files changed, 383 insertions, 266 deletions
diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp
index 6c97a64ed7..bcff03ceaa 100644
--- a/indra/llaudio/llaudiodecodemgr.cpp
+++ b/indra/llaudio/llaudiodecodemgr.cpp
@@ -40,6 +40,7 @@
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
+#include <iterator>
extern LLAudioEngine *gAudiop;
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
diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp
index 01da20f060..1722b48f44 100644
--- a/indra/llmessage/llbuffer.cpp
+++ b/indra/llmessage/llbuffer.cpp
@@ -32,6 +32,7 @@
#include "llmath.h"
#include "llstl.h"
#include "llthread.h"
+#include <iterator>
#define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED llassert(!mMutexp || mMutexp->isSelfLocked());
diff --git a/indra/llmessage/lldispatcher.cpp b/indra/llmessage/lldispatcher.cpp
index b2dc414a68..7ac3651a76 100644
--- a/indra/llmessage/lldispatcher.cpp
+++ b/indra/llmessage/lldispatcher.cpp
@@ -29,6 +29,7 @@
#include "lldispatcher.h"
#include <algorithm>
+#include <iterator>
#include "llstl.h"
#include "message.h"