summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt20
-rw-r--r--indra/llcommon/llallocator.cpp33
-rw-r--r--indra/llcommon/llallocator.h6
-rw-r--r--indra/llcommon/llapr.cpp81
-rw-r--r--indra/llcommon/llapr.h42
-rw-r--r--indra/llcommon/llcommon.cpp7
-rw-r--r--indra/llcommon/lldate.cpp14
-rw-r--r--indra/llcommon/lldate.h5
-rw-r--r--indra/llcommon/lldefs.h3
-rw-r--r--indra/llcommon/llerrorlegacy.h9
-rw-r--r--indra/llcommon/llevents.cpp1
-rw-r--r--indra/llcommon/llfasttimer.cpp447
-rw-r--r--indra/llcommon/llfasttimer.h294
-rw-r--r--indra/llcommon/llfasttimer_class.cpp921
-rw-r--r--indra/llcommon/llfasttimer_class.h276
-rw-r--r--indra/llcommon/llfile.cpp2
-rw-r--r--indra/llcommon/llfindlocale.cpp2
-rw-r--r--indra/llcommon/llinitparam.cpp43
-rw-r--r--indra/llcommon/llinitparam.h348
-rw-r--r--indra/llcommon/llinstancetracker.cpp18
-rw-r--r--indra/llcommon/llinstancetracker.h37
-rw-r--r--indra/llcommon/llleap.cpp2
-rw-r--r--indra/llcommon/llmd5.cpp1
-rw-r--r--indra/llcommon/llmemory.cpp1
-rw-r--r--indra/llcommon/llmemory.h7
-rw-r--r--indra/llcommon/llmemtype.cpp232
-rw-r--r--indra/llcommon/llmemtype.h242
-rw-r--r--indra/llcommon/llmetricperformancetester.cpp7
-rw-r--r--indra/llcommon/llmortician.h1
-rw-r--r--indra/llcommon/llmutex.cpp176
-rw-r--r--indra/llcommon/llmutex.h101
-rw-r--r--indra/llcommon/llpointer.h85
-rw-r--r--indra/llcommon/llpredicate.cpp41
-rw-r--r--indra/llcommon/llpredicate.h210
-rw-r--r--indra/llcommon/llprocess.h3
-rw-r--r--indra/llcommon/llprocessor.cpp6
-rw-r--r--indra/llcommon/llprocessor.h4
-rw-r--r--indra/llcommon/llqueuedthread.cpp8
-rw-r--r--indra/llcommon/llsdparam.cpp52
-rw-r--r--indra/llcommon/llsdparam.h20
-rw-r--r--indra/llcommon/llsingleton.h52
-rw-r--r--indra/llcommon/llskipmap.h6
-rw-r--r--indra/llcommon/llstacktrace.cpp2
-rw-r--r--indra/llcommon/llstat.cpp1311
-rw-r--r--indra/llcommon/llstat.h353
-rw-r--r--indra/llcommon/llstatenums.h2
-rw-r--r--indra/llcommon/llstl.h1
-rw-r--r--indra/llcommon/llstring.cpp5
-rw-r--r--indra/llcommon/llstring.h3
-rw-r--r--indra/llcommon/llsys.cpp5
-rw-r--r--indra/llcommon/llthread.cpp176
-rw-r--r--indra/llcommon/llthread.h83
-rw-r--r--indra/llcommon/llthreadlocalstorage.h275
-rw-r--r--indra/llcommon/lltimer.cpp20
-rw-r--r--indra/llcommon/lltimer.h21
-rw-r--r--indra/llcommon/lltrace.cpp110
-rw-r--r--indra/llcommon/lltrace.h836
-rw-r--r--indra/llcommon/lltracerecording.cpp636
-rw-r--r--indra/llcommon/lltracerecording.h410
-rw-r--r--indra/llcommon/lltracethreadrecorder.cpp287
-rw-r--r--indra/llcommon/lltracethreadrecorder.h123
-rw-r--r--indra/llcommon/llunit.h475
-rw-r--r--indra/llcommon/lluuid.cpp4
-rw-r--r--indra/llcommon/llwin32headers.h36
-rw-r--r--indra/llcommon/llwin32headerslean.h36
-rw-r--r--indra/llcommon/llworkerthread.h5
-rw-r--r--indra/llcommon/tests/llunits_test.cpp208
67 files changed, 5365 insertions, 3924 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 66e2bc9095..28677b036d 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -53,7 +53,7 @@ set(llcommon_SOURCE_FILES
lleventfilter.cpp
llevents.cpp
lleventtimer.cpp
- llfasttimer_class.cpp
+ llfasttimer.cpp
llfile.cpp
llfindlocale.cpp
llfixedbuffer.cpp
@@ -71,12 +71,13 @@ set(llcommon_SOURCE_FILES
llmd5.cpp
llmemory.cpp
llmemorystream.cpp
- llmemtype.cpp
llmetrics.cpp
llmetricperformancetester.cpp
llmortician.cpp
+ llmutex.cpp
lloptioninterface.cpp
llptrto.cpp
+ llpredicate.cpp
llprocess.cpp
llprocessor.cpp
llqueuedthread.cpp
@@ -90,7 +91,6 @@ set(llcommon_SOURCE_FILES
llsdutil.cpp
llsecondlifeurls.cpp
llsingleton.cpp
- llstat.cpp
llstacktrace.cpp
llstreamqueue.cpp
llstreamtools.cpp
@@ -100,6 +100,9 @@ set(llcommon_SOURCE_FILES
llthread.cpp
llthreadsafequeue.cpp
lltimer.cpp
+ lltrace.cpp
+ lltracerecording.cpp
+ lltracethreadrecorder.cpp
lluri.cpp
lluuid.cpp
llworkerthread.cpp
@@ -168,7 +171,6 @@ set(llcommon_HEADER_FILES
lleventemitter.h
llextendedstatus.h
llfasttimer.h
- llfasttimer_class.h
llfile.h
llfindlocale.h
llfixedbuffer.h
@@ -197,13 +199,14 @@ set(llcommon_HEADER_FILES
llmd5.h
llmemory.h
llmemorystream.h
- llmemtype.h
llmetrics.h
llmetricperformancetester.h
llmortician.h
+ llmutex.h
llnametable.h
lloptioninterface.h
llpointer.h
+ llpredicate.h
llpreprocessor.h
llpriqueuemap.h
llprocess.h
@@ -231,7 +234,6 @@ set(llcommon_HEADER_FILES
llsortedvector.h
llstack.h
llstacktrace.h
- llstat.h
llstatenums.h
llstl.h
llstreamqueue.h
@@ -241,10 +243,15 @@ set(llcommon_HEADER_FILES
llstringtable.h
llsys.h
llthread.h
+ llthreadlocalstorage.h
llthreadsafequeue.h
lltimer.h
+ lltrace.h
+ lltracerecording.h
+ lltracethreadrecorder.h
lltreeiterators.h
lltypeinfolookup.h
+ llunit.h
lluri.h
lluuid.h
lluuidhashmap.h
@@ -337,6 +344,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
+ LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp
index 87654b5b97..34fc28d8cc 100644
--- a/indra/llcommon/llallocator.cpp
+++ b/indra/llcommon/llallocator.cpp
@@ -35,28 +35,6 @@
DECLARE_bool(heap_profile_use_stack_trace);
//DECLARE_double(tcmalloc_release_rate);
-// static
-void LLAllocator::pushMemType(S32 type)
-{
- if(isProfiling())
- {
- PushMemType(type);
- }
-}
-
-// static
-S32 LLAllocator::popMemType()
-{
- if (isProfiling())
- {
- return PopMemType();
- }
- else
- {
- return -1;
- }
-}
-
void LLAllocator::setProfilingEnabled(bool should_enable)
{
// NULL disables dumping to disk
@@ -94,17 +72,6 @@ std::string LLAllocator::getRawProfile()
// stub implementations for when tcmalloc is disabled
//
-// static
-void LLAllocator::pushMemType(S32 type)
-{
-}
-
-// static
-S32 LLAllocator::popMemType()
-{
- return -1;
-}
-
void LLAllocator::setProfilingEnabled(bool should_enable)
{
}
diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h
index a91dd57d14..d26ad73c5b 100644
--- a/indra/llcommon/llallocator.h
+++ b/indra/llcommon/llallocator.h
@@ -29,16 +29,10 @@
#include <string>
-#include "llmemtype.h"
#include "llallocator_heap_profile.h"
class LL_COMMON_API LLAllocator {
friend class LLMemoryView;
- friend class LLMemType;
-
-private:
- static void pushMemType(S32 type);
- static S32 popMemType();
public:
void setProfilingEnabled(bool should_enable);
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index d1c44c9403..d911f258b6 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -29,6 +29,7 @@
#include "linden_common.h"
#include "llapr.h"
#include "apr_dso.h"
+#include "llthreadlocalstorage.h"
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
@@ -52,8 +53,10 @@ void ll_init_apr()
if(!LLAPRFile::sAPRFilePoolp)
{
- LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
+ LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE);
}
+
+ LLThreadLocalPointerBase::initAllThreadLocalStorage();
}
@@ -77,6 +80,9 @@ void ll_cleanup_apr()
apr_thread_mutex_destroy(gCallStacksLogMutexp);
gCallStacksLogMutexp = NULL;
}
+
+ LLThreadLocalPointerBase::destroyAllThreadLocalStorage();
+
if (gAPRPoolp)
{
apr_pool_destroy(gAPRPoolp);
@@ -84,7 +90,7 @@ void ll_cleanup_apr()
}
if (LLAPRFile::sAPRFilePoolp)
{
- delete LLAPRFile::sAPRFilePoolp ;
+ delete LLAPRFile::sAPRFilePoolp ;
LLAPRFile::sAPRFilePoolp = NULL ;
}
apr_terminate();
@@ -477,6 +483,77 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset)
}
//
+//LLThreadLocalPointerBase
+//
+bool LLThreadLocalPointerBase::sInitialized = false;
+
+void LLThreadLocalPointerBase::set( void* value )
+{
+ llassert(sInitialized && mThreadKey);
+
+ apr_status_t result = apr_threadkey_private_set((void*)value, mThreadKey);
+ if (result != APR_SUCCESS)
+ {
+ ll_apr_warn_status(result);
+ llerrs << "Failed to set thread local data" << llendl;
+ }
+}
+
+void LLThreadLocalPointerBase::initStorage( )
+{
+ apr_status_t result = apr_threadkey_private_create(&mThreadKey, NULL, gAPRPoolp);
+ if (result != APR_SUCCESS)
+ {
+ ll_apr_warn_status(result);
+ llerrs << "Failed to allocate thread local data" << llendl;
+ }
+}
+
+void LLThreadLocalPointerBase::destroyStorage()
+{
+ if (sInitialized)
+ {
+ if (mThreadKey)
+ {
+ apr_status_t result = apr_threadkey_private_delete(mThreadKey);
+ if (result != APR_SUCCESS)
+ {
+ ll_apr_warn_status(result);
+ llerrs << "Failed to delete thread local data" << llendl;
+ }
+ }
+ }
+}
+
+void LLThreadLocalPointerBase::initAllThreadLocalStorage()
+{
+ if (!sInitialized)
+ {
+ for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
+ it != end_it;
+ ++it)
+ {
+ (*it).initStorage();
+ }
+ sInitialized = true;
+ }
+}
+
+void LLThreadLocalPointerBase::destroyAllThreadLocalStorage()
+{
+ if (sInitialized)
+ {
+ //for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
+ // it != end_it;
+ // ++it)
+ //{
+ // (*it).destroyStorage();
+ //}
+ sInitialized = false;
+ }
+}
+
+//
//*******************************************************************************************************************************
//static components of LLAPRFile
//
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 034546c3f3..b3c9bfd58c 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -32,14 +32,6 @@
#if LL_LINUX || LL_SOLARIS
#include <sys/param.h> // Need PATH_MAX in APR headers...
#endif
-#if LL_WINDOWS
- // Limit Windows API to small and manageable set.
- // If you get undefined symbols, find the appropriate
- // Windows header file and include that in your .cpp file.
- #define WIN32_LEAN_AND_MEAN
- #include <winsock2.h>
- #include <windows.h>
-#endif
#include <boost/noncopyable.hpp>
@@ -48,12 +40,26 @@
#include "apr_getopt.h"
#include "apr_signal.h"
#include "apr_atomic.h"
+
#include "llstring.h"
extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
extern apr_thread_mutex_t* gCallStacksLogMutexp;
struct apr_dso_handle_t;
+/**
+ * @brief Function which appropriately logs error or remains quiet on
+ * APR_SUCCESS.
+ * @return Returns <code>true</code> if status is an error condition.
+ */
+bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
+/// There's a whole other APR error-message function if you pass a DSO handle.
+bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle);
+
+void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
+void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
+
+extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
/**
* @brief initialize the common apr constructs -- apr itself, the
@@ -163,14 +169,17 @@ public:
LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
~LLAtomic32<Type>() {};
- operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
+ operator const Type() { return get(); }
Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
- Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
+ Type operator ++() { apr_atomic_inc32(&mData); return get(); } // ++Type
+ Type operator --(int) { const Type result(get()); apr_atomic_dec32(&mData); return result; } // Type--
+ Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
private:
+ const Type get() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
apr_uint32_t mData;
};
@@ -255,18 +264,5 @@ public:
//*******************************************************************************************************************************
};
-/**
- * @brief Function which appropriately logs error or remains quiet on
- * APR_SUCCESS.
- * @return Returns <code>true</code> if status is an error condition.
- */
-bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
-/// There's a whole other APR error-message function if you pass a DSO handle.
-bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle);
-
-void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
-void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
-
-extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
#endif // LL_LLAPR_H
diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 8be9e4f4de..c720df7555 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -29,6 +29,7 @@
#include "llmemory.h"
#include "llthread.h"
+#include "lltrace.h"
//static
BOOL LLCommon::sAprInitialized = FALSE;
@@ -44,15 +45,13 @@ void LLCommon::initClass()
}
LLTimer::initClass();
LLThreadSafeRefCount::initThreadSafeRefCount();
-// LLWorkerThread::initClass();
-// LLFrameCallbackManager::initClass();
+ LLTrace::init();
}
//static
void LLCommon::cleanupClass()
{
-// LLFrameCallbackManager::cleanupClass();
-// LLWorkerThread::cleanupClass();
+ LLTrace::cleanup();
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
LLTimer::cleanupClass();
if (sAprInitialized)
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index 030ef6a3c7..2efe39e158 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -39,6 +39,7 @@
#include "lltimer.h"
#include "llstring.h"
+#include "llfasttimer.h"
static const F64 DATE_EPOCH = 0.0;
@@ -48,18 +49,15 @@ static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH)
-{
-}
+{}
LLDate::LLDate(const LLDate& date) :
mSecondsSinceEpoch(date.mSecondsSinceEpoch)
-{
-}
+{}
-LLDate::LLDate(F64 seconds_since_epoch) :
- mSecondsSinceEpoch(seconds_since_epoch)
-{
-}
+LLDate::LLDate(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch) :
+ mSecondsSinceEpoch(seconds_since_epoch.value())
+{}
LLDate::LLDate(const std::string& iso8601_date)
{
diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h
index 7ff8b550ad..b62a846147 100644
--- a/indra/llcommon/lldate.h
+++ b/indra/llcommon/lldate.h
@@ -33,6 +33,7 @@
#include <string>
#include "stdtypes.h"
+#include "llunit.h"
/**
* @class LLDate
@@ -56,9 +57,9 @@ public:
/**
* @brief Construct a date from a seconds since epoch value.
*
- * @pararm seconds_since_epoch The number of seconds since UTC epoch.
+ * @param seconds_since_epoch The number of seconds since UTC epoch.
*/
- LLDate(F64 seconds_since_epoch);
+ LLDate(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch);
/**
* @brief Construct a date from a string representation
diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h
index 5a4b8325f4..d57b9dccff 100644
--- a/indra/llcommon/lldefs.h
+++ b/indra/llcommon/lldefs.h
@@ -244,5 +244,8 @@ inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs)
rhs = tmp;
}
+#define LL_GLUE_IMPL(x, y) x##y
+#define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y)
+
#endif // LL_LLDEFS_H
diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h
index 37cee579cd..097a533b1a 100644
--- a/indra/llcommon/llerrorlegacy.h
+++ b/indra/llcommon/llerrorlegacy.h
@@ -29,6 +29,7 @@
#define LL_LLERRORLEGACY_H
#include "llpreprocessor.h"
+#include <boost/static_assert.hpp>
/*
LEGACY -- DO NOT USE THIS STUFF ANYMORE
@@ -111,6 +112,14 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
#define llverify(func) do {if (func) {}} while(0)
#endif
+#ifdef LL_WINDOWS
+#define llstatic_assert(func, msg) static_assert(func, msg)
+#define llstatic_assert_template(type, func, msg) static_assert(func, msg)
+#else
+#define llstatic_assert(func, msg) BOOST_STATIC_ASSERT(func)
+#define llstatic_assert_template(type, func, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && func);
+#endif
+
// handy compile-time assert - enforce those template parameters!
#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */
//XXX: used in two places in llcommon/llskipmap.h
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index 0855180dcd..1c928b3db8 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -41,7 +41,6 @@
#include <algorithm>
// std headers
#include <typeinfo>
-#include <cassert>
#include <cmath>
#include <cctype>
// external library headers
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
new file mode 100644
index 0000000000..e6233a094e
--- /dev/null
+++ b/indra/llcommon/llfasttimer.cpp
@@ -0,0 +1,447 @@
+/**
+ * @file llfasttimer.cpp
+ * @brief Implementation of the fast timer.
+ *
+ * $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$
+ */
+#include "linden_common.h"
+
+#include "llfasttimer.h"
+
+#include "llmemory.h"
+#include "llprocessor.h"
+#include "llsingleton.h"
+#include "lltreeiterators.h"
+#include "llsdserialize.h"
+#include "llunit.h"
+#include "llsd.h"
+#include "lltracerecording.h"
+#include "lltracethreadrecorder.h"
+
+#include <boost/bind.hpp>
+#include <queue>
+
+
+#if LL_WINDOWS
+#include "lltimer.h"
+#elif LL_LINUX || LL_SOLARIS
+#include <sys/time.h>
+#include <sched.h>
+#include "lltimer.h"
+#elif LL_DARWIN
+#include <sys/time.h>
+#include "lltimer.h" // get_clock_count()
+#else
+#error "architecture not supported"
+#endif
+
+namespace LLTrace
+{
+
+//////////////////////////////////////////////////////////////////////////////
+// statics
+
+bool TimeBlock::sLog = false;
+std::string TimeBlock::sLogName = "";
+bool TimeBlock::sMetricLog = false;
+
+#if LL_LINUX || LL_SOLARIS
+U64 TimeBlock::sClockResolution = 1000000000; // Nanosecond resolution
+#else
+U64 TimeBlock::sClockResolution = 1000000; // Microsecond resolution
+#endif
+
+static LLMutex* sLogLock = NULL;
+static std::queue<LLSD> sLogQueue;
+
+
+// FIXME: move these declarations to the relevant modules
+
+// helper functions
+typedef LLTreeDFSPostIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_bottom_up_iterator_t;
+
+static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(TimeBlock& id)
+{
+ return timer_tree_bottom_up_iterator_t(&id,
+ boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1),
+ boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
+}
+
+static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
+{
+ return timer_tree_bottom_up_iterator_t();
+}
+
+typedef LLTreeDFSIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_dfs_iterator_t;
+
+
+static timer_tree_dfs_iterator_t begin_timer_tree(TimeBlock& id)
+{
+ return timer_tree_dfs_iterator_t(&id,
+ boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1),
+ boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
+}
+
+static timer_tree_dfs_iterator_t end_timer_tree()
+{
+ return timer_tree_dfs_iterator_t();
+}
+
+
+// sort child timers by name
+struct SortTimerByName
+{
+ bool operator()(const TimeBlock* i1, const TimeBlock* i2)
+ {
+ return i1->getName() < i2->getName();
+ }
+};
+
+TimeBlock& TimeBlock::getRootTimeBlock()
+{
+ static TimeBlock root_timer("root", true, NULL);
+ return root_timer;
+}
+
+void TimeBlock::pushLog(LLSD log)
+{
+ LLMutexLock lock(sLogLock);
+
+ sLogQueue.push(log);
+}
+
+void TimeBlock::setLogLock(LLMutex* lock)
+{
+ sLogLock = lock;
+}
+
+
+//static
+#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+U64 TimeBlock::countsPerSecond()
+{
+ return sClockResolution;
+}
+#else // windows or x86-mac or x86-linux or x86-solaris
+U64 TimeBlock::countsPerSecond()
+{
+#if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS
+ //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
+ static LLUnit<LLUnits::Hertz, U64> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency();
+
+#else
+ // If we're not using RDTSC, each fast timer tick is just a performance counter tick.
+ // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
+ // since that would change displayed MHz stats for CPUs
+ static bool firstcall = true;
+ static U64 sCPUClockFrequency;
+ if (firstcall)
+ {
+ QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
+ firstcall = false;
+ }
+#endif
+ return sCPUClockFrequency.value();
+}
+#endif
+
+TimeBlock::TimeBlock(const char* name, bool open, TimeBlock* parent)
+: TraceType<TimeBlockAccumulator>(name),
+ mCollapsed(true)
+{
+ setCollapsed(!open);
+}
+
+TimeBlockTreeNode& TimeBlock::getTreeNode() const
+{
+ TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex());
+ llassert(nodep);
+ return *nodep;
+}
+
+// static
+void TimeBlock::processTimes()
+{
+ get_clock_count(); // good place to calculate clock frequency
+ U64 cur_time = getCPUClockCount64();
+ BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();
+
+ // set up initial tree
+ for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
+ it != end_it;
+ ++it)
+ {
+ TimeBlock& timer = *it;
+ if (&timer == &TimeBlock::getRootTimeBlock()) continue;
+
+ // bootstrap tree construction by attaching to last timer to be on stack
+ // when this timer was called
+ if (timer.getParent() == &TimeBlock::getRootTimeBlock())
+ {
+ TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
+
+ if (accumulator->mLastCaller)
+ {
+ timer.setParent(accumulator->mLastCaller);
+ accumulator->mParent = accumulator->mLastCaller;
+ }
+ // no need to push up tree on first use, flag can be set spuriously
+ accumulator->mMoveUpTree = false;
+ }
+ }
+
+ // bump timers up tree if they have been flagged as being in the wrong place
+ // do this in a bottom up order to promote descendants first before promoting ancestors
+ // this preserves partial order derived from current frame's observations
+ 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
+ TimeBlockTreeNode& tree_node = timerp->getTreeNode();
+ if (tree_node.mNeedsSorting)
+ {
+ std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName());
+ }
+
+ // skip root timer
+ if (timerp != &TimeBlock::getRootTimeBlock())
+ {
+ TimeBlockAccumulator* accumulator = timerp->getPrimaryAccumulator();
+
+ if (accumulator->mMoveUpTree)
+ {
+ // since ancestors have already been visited, re-parenting won't affect tree traversal
+ //step up tree, bringing our descendants with us
+ LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
+ " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL;
+ timerp->setParent(timerp->getParent()->getParent());
+ accumulator->mParent = timerp->getParent();
+ accumulator->mMoveUpTree = false;
+
+ // don't bubble up any ancestors until descendants are done bubbling up
+ // as ancestors may call this timer only on certain paths, so we want to resolve
+ // child-most block locations before their parents
+ it.skipAncestors();
+ }
+ }
+ }
+
+ // walk up stack of active timers and accumulate current time while leaving timing structures active
+ 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.mActiveTimer != cur_timer)
+ {
+ U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
+ 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;
+
+ stack_record = &cur_timer->mLastTimerData;
+ stack_record->mChildTime += cumulative_time_delta;
+ if (stack_record->mTimeBlock)
+ {
+ accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
+ }
+
+ cur_timer = cur_timer->mLastTimerData.mActiveTimer;
+ }
+
+
+ // reset for next frame
+ for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
+ end_it = LLInstanceTracker<TimeBlock>::endInstances();
+ it != end_it;
+ ++it)
+ {
+ TimeBlock& timer = *it;
+ TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
+
+ accumulator->mLastCaller = NULL;
+ accumulator->mMoveUpTree = false;
+ }
+
+ // traverse tree in DFS post order, or bottom up
+ //for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimer());
+ // it != end_timer_tree_bottom_up();
+ // ++it)
+ //{
+ // TimeBlock* timerp = (*it);
+ // TimeBlockAccumulator& accumulator = timerp->getPrimaryAccumulator();
+ // timerp->mTreeTimeCounter = accumulator.mSelfTimeCounter;
+ // for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
+ // {
+ // timerp->mTreeTimeCounter += (*child_it)->mTreeTimeCounter;
+ // }
+ //}
+}
+
+
+std::vector<TimeBlock*>::iterator TimeBlock::beginChildren()
+{
+ return getTreeNode().mChildren.begin();
+}
+
+std::vector<TimeBlock*>::iterator TimeBlock::endChildren()
+{
+ return getTreeNode().mChildren.end();
+}
+
+std::vector<TimeBlock*>& TimeBlock::getChildren()
+{
+ return getTreeNode().mChildren;
+}
+
+//static
+void TimeBlock::logStats()
+{
+ // get ready for next frame
+ if (sLog)
+ { //output current frame counts to performance log
+
+ static S32 call_count = 0;
+ if (call_count % 100 == 0)
+ {
+ LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL;
+ LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL;
+ LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL;
+ LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL;
+ LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64()) / (LLUnit<LLUnits::Hertz, F64>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;
+ }
+ call_count++;
+
+ LLUnit<LLUnits::Seconds, F64> total_time(0);
+ LLSD sd;
+
+ {
+ for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
+ end_it = LLInstanceTracker<TimeBlock>::endInstances();
+ it != end_it;
+ ++it)
+ {
+ TimeBlock& timer = *it;
+ LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
+ sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecordingPeriod().getSum(timer).value());
+ sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecordingPeriod().getSum(timer.callCount()));
+
+ // computing total time here because getting the root timer's getCountHistory
+ // doesn't work correctly on the first frame
+ total_time += frame_recording.getLastRecordingPeriod().getSum(timer);
+ }
+ }
+
+ sd["Total"]["Time"] = (LLSD::Real) total_time.value();
+ sd["Total"]["Calls"] = (LLSD::Integer) 1;
+
+ {
+ LLMutexLock lock(sLogLock);
+ sLogQueue.push(sd);
+ }
+ }
+
+}
+
+//static
+void TimeBlock::dumpCurTimes()
+{
+ LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
+ 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::getRootTimeBlock());
+ it != end_timer_tree();
+ ++it)
+ {
+ TimeBlock* timerp = (*it);
+ LLUnit<LLUnits::Seconds, F64> total_time_ms = last_frame_recording.getSum(*timerp);
+ U32 num_calls = last_frame_recording.getSum(timerp->callCount());
+
+ // Don't bother with really brief times, keep output concise
+ if (total_time_ms < 0.1) continue;
+
+ std::ostringstream out_str;
+ TimeBlock* parent_timerp = timerp;
+ while(parent_timerp && parent_timerp != parent_timerp->getParent())
+ {
+ out_str << "\t";
+ parent_timerp = parent_timerp->getParent();
+ }
+
+ out_str << timerp->getName() << " "
+ << std::setprecision(3) << total_time_ms.as<LLUnits::Milliseconds, F32>().value() << " ms, "
+ << num_calls << " calls";
+
+ llinfos << out_str.str() << llendl;
+ }
+}
+
+//static
+void TimeBlock::writeLog(std::ostream& os)
+{
+ while (!sLogQueue.empty())
+ {
+ LLSD& sd = sLogQueue.front();
+ LLSDSerialize::toXML(sd, os);
+ LLMutexLock lock(sLogLock);
+ sLogQueue.pop();
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// TimeBlockAccumulator
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TimeBlockAccumulator::TimeBlockAccumulator()
+: mSelfTimeCounter(0),
+ mTotalTimeCounter(0),
+ mCalls(0),
+ mLastCaller(NULL),
+ mActiveCount(0),
+ mMoveUpTree(false),
+ mParent(NULL)
+{}
+
+void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other )
+{
+ mSelfTimeCounter += other.mSelfTimeCounter;
+ mTotalTimeCounter += other.mTotalTimeCounter;
+ mCalls += other.mCalls;
+ mLastCaller = other.mLastCaller;
+ mActiveCount = other.mActiveCount;
+ mMoveUpTree = other.mMoveUpTree;
+ mParent = other.mParent;
+}
+
+void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other )
+{
+ mTotalTimeCounter = 0;
+ mSelfTimeCounter = 0;
+ mCalls = 0;
+}
+
+} // namespace LLTrace
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 2b25f2fabb..fb2868ff98 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -1,6 +1,6 @@
/**
* @file llfasttimer.h
- * @brief Inline implementations of fast timers.
+ * @brief Declaration of a fast timer.
*
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -27,9 +27,295 @@
#ifndef LL_FASTTIMER_H
#define LL_FASTTIMER_H
-// Implementation of getCPUClockCount32() and getCPUClockCount64 are now in llfastertimer_class.cpp.
+#include "llinstancetracker.h"
+#include "lltrace.h"
-// pull in the actual class definition
-#include "llfasttimer_class.h"
+#define FAST_TIMER_ON 1
+#define LL_FASTTIMER_USE_RDTSC 1
+
+class LLMutex;
+
+namespace LLTrace
+{
+
+struct BlockTimerStackRecord
+{
+ class BlockTimer* mActiveTimer;
+ class TimeBlock* mTimeBlock;
+ U64 mChildTime;
+};
+
+class ThreadTimerStack
+: public BlockTimerStackRecord,
+ public LLThreadLocalSingleton<ThreadTimerStack>
+{
+ friend class LLThreadLocalSingleton<ThreadTimerStack>;
+ ThreadTimerStack()
+ {}
+
+public:
+ ThreadTimerStack& operator=(const BlockTimerStackRecord& other)
+ {
+ BlockTimerStackRecord::operator=(other);
+ return *this;
+ }
+};
+
+class BlockTimer
+{
+public:
+ friend class TimeBlock;
+ typedef BlockTimer self_t;
+ typedef class TimeBlock DeclareTimer;
+
+ BlockTimer(TimeBlock& timer);
+ ~BlockTimer();
+
+private:
+
+ U64 mStartTime;
+ BlockTimerStackRecord mLastTimerData;
+};
+
+// stores a "named" timer instance to be reused via multiple BlockTimer stack instances
+class TimeBlock
+: public TraceType<TimeBlockAccumulator>,
+ public LLInstanceTracker<TimeBlock>
+{
+public:
+ TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimeBlock());
+
+ TimeBlockTreeNode& getTreeNode() const;
+ TimeBlock* getParent() const { return getTreeNode().getParent(); }
+ void setParent(TimeBlock* parent) { getTreeNode().setParent(parent); }
+
+ typedef std::vector<TimeBlock*>::iterator child_iter;
+ typedef std::vector<TimeBlock*>::const_iterator child_const_iter;
+ child_iter beginChildren();
+ child_iter endChildren();
+ std::vector<TimeBlock*>& getChildren();
+
+ void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
+ bool getCollapsed() const { return mCollapsed; }
+
+ TraceType<TimeBlockAccumulator::CallCountAspect>& callCount()
+ {
+ return static_cast<TraceType<TimeBlockAccumulator::CallCountAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
+ }
+
+ TraceType<TimeBlockAccumulator::SelfTimeAspect>& selfTime()
+ {
+ return static_cast<TraceType<TimeBlockAccumulator::SelfTimeAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
+ }
+
+ static TimeBlock& getRootTimeBlock();
+ static void pushLog(LLSD sd);
+ static void setLogLock(LLMutex* mutex);
+ static void writeLog(std::ostream& os);
+
+ // dumps current cumulative frame stats to log
+ // call nextFrame() to reset timers
+ static void dumpCurTimes();
+
+ //////////////////////////////////////////////////////////////////////////////
+ //
+ // Important note: These implementations must be FAST!
+ //
+
+
+#if LL_WINDOWS
+ //
+ // Windows implementation of CPU clock
+ //
+
+ //
+ // NOTE: put back in when we aren't using platform sdk anymore
+ //
+ // because MS has different signatures for these functions in winnt.h
+ // need to rename them to avoid conflicts
+ //#define _interlockedbittestandset _renamed_interlockedbittestandset
+ //#define _interlockedbittestandreset _renamed_interlockedbittestandreset
+ //#include <intrin.h>
+ //#undef _interlockedbittestandset
+ //#undef _interlockedbittestandreset
+
+ //inline U32 TimeBlock::getCPUClockCount32()
+ //{
+ // U64 time_stamp = __rdtsc();
+ // return (U32)(time_stamp >> 8);
+ //}
+ //
+ //// return full timer value, *not* shifted by 8 bits
+ //inline U64 TimeBlock::getCPUClockCount64()
+ //{
+ // return __rdtsc();
+ //}
+
+ // shift off lower 8 bits for lower resolution but longer term timing
+ // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
+#if LL_FASTTIMER_USE_RDTSC
+ static U32 getCPUClockCount32()
+ {
+ U32 ret_val;
+ __asm
+ {
+ _emit 0x0f
+ _emit 0x31
+ shr eax,8
+ shl edx,24
+ or eax, edx
+ mov dword ptr [ret_val], eax
+ }
+ return ret_val;
+ }
+
+ // return full timer value, *not* shifted by 8 bits
+ static U64 getCPUClockCount64()
+ {
+ U64 ret_val;
+ __asm
+ {
+ _emit 0x0f
+ _emit 0x31
+ mov eax,eax
+ mov edx,edx
+ mov dword ptr [ret_val+4], edx
+ mov dword ptr [ret_val], eax
+ }
+ return ret_val;
+ }
+
+#else
+ //U64 get_clock_count(); // in lltimer.cpp
+ // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
+ static U32 getCPUClockCount32()
+ {
+ return (U32)(get_clock_count()>>8);
+ }
+
+ static U64 getCPUClockCount64()
+ {
+ return get_clock_count();
+ }
+
+#endif
+
+#endif
+
+
+#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+ //
+ // Linux and Solaris implementation of CPU clock - non-x86.
+ // This is accurate but SLOW! Only use out of desperation.
+ //
+ // Try to use the MONOTONIC clock if available, this is a constant time counter
+ // with nanosecond resolution (but not necessarily accuracy) and attempts are
+ // made to synchronize this value between cores at kernel start. It should not
+ // be affected by CPU frequency. If not available use the REALTIME clock, but
+ // this may be affected by NTP adjustments or other user activity affecting
+ // the system time.
+ static U64 getCPUClockCount64()
+ {
+ struct timespec tp;
+
+#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
+ if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
+#endif
+ clock_gettime(CLOCK_REALTIME,&tp);
+
+ return (tp.tv_sec*sClockResolution)+tp.tv_nsec;
+ }
+
+ static U32 getCPUClockCount32()
+ {
+ return (U32)(getCPUClockCount64() >> 8);
+ }
+
+#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+
+
+#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+ //
+ // Mac+Linux+Solaris FAST x86 implementation of CPU clock
+ static U32 getCPUClockCount32()
+ {
+ U64 x;
+ __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+ return (U32)(x >> 8);
+ }
+
+ static U64 getCPUClockCount64()
+ {
+ U64 x;
+ __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+ return x;
+ }
+
+#endif
+
+ static U64 countsPerSecond();
+
+ // updates cumulative times and hierarchy,
+ // can be called multiple times in a frame, at any point
+ static void processTimes();
+
+ // call this once a frame to periodically log timers
+ static void logStats();
+
+ bool mCollapsed; // don't show children
+
+ // statics
+ static std::string sLogName;
+ static bool sMetricLog,
+ sLog;
+ static U64 sClockResolution;
+};
+
+LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)
+{
+#if FAST_TIMER_ON
+ mStartTime = TimeBlock::getCPUClockCount64();
+
+ 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);
+
+ // store top of stack
+ mLastTimerData = *cur_timer_data;
+ // push new information
+ cur_timer_data->mActiveTimer = this;
+ cur_timer_data->mTimeBlock = &timer;
+ cur_timer_data->mChildTime = 0;
+#endif
+}
+
+LL_FORCE_INLINE BlockTimer::~BlockTimer()
+{
+#if FAST_TIMER_ON
+ U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
+ BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
+ TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();
+
+ accumulator->mCalls++;
+ accumulator->mSelfTimeCounter += total_time - cur_timer_data->mChildTime;
+ accumulator->mTotalTimeCounter += total_time;
+ accumulator->mActiveCount--;
+
+ // store last caller to bootstrap tree creation
+ // do this in the destructor in case of recursion to get topmost caller
+ accumulator->mLastCaller = mLastTimerData.mTimeBlock;
+
+ // we are only tracking self time, so subtract our total time delta from parents
+ mLastTimerData.mChildTime += total_time;
+
+ *ThreadTimerStack::getIfExists() = mLastTimerData;
+#endif
+}
+
+}
+
+typedef LLTrace::BlockTimer LLFastTimer;
#endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp
deleted file mode 100644
index 463f558c2c..0000000000
--- a/indra/llcommon/llfasttimer_class.cpp
+++ /dev/null
@@ -1,921 +0,0 @@
-/**
- * @file llfasttimer_class.cpp
- * @brief Implementation of the fast timer.
- *
- * $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$
- */
-#include "linden_common.h"
-
-#include "llfasttimer.h"
-
-#include "llmemory.h"
-#include "llprocessor.h"
-#include "llsingleton.h"
-#include "lltreeiterators.h"
-#include "llsdserialize.h"
-
-#include <boost/bind.hpp>
-
-
-#if LL_WINDOWS
-#include "lltimer.h"
-#elif LL_LINUX || LL_SOLARIS
-#include <sys/time.h>
-#include <sched.h>
-#include "lltimer.h"
-#elif LL_DARWIN
-#include <sys/time.h>
-#include "lltimer.h" // get_clock_count()
-#else
-#error "architecture not supported"
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// statics
-
-S32 LLFastTimer::sCurFrameIndex = -1;
-S32 LLFastTimer::sLastFrameIndex = -1;
-U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64();
-bool LLFastTimer::sPauseHistory = 0;
-bool LLFastTimer::sResetHistory = 0;
-LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
-BOOL LLFastTimer::sLog = FALSE;
-std::string LLFastTimer::sLogName = "";
-BOOL LLFastTimer::sMetricLog = FALSE;
-LLMutex* LLFastTimer::sLogLock = NULL;
-std::queue<LLSD> LLFastTimer::sLogQueue;
-
-#define USE_RDTSC 0
-
-#if LL_LINUX || LL_SOLARIS
-U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
-#else
-U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
-#endif
-
-std::vector<LLFastTimer::FrameState>* LLFastTimer::sTimerInfos = NULL;
-U64 LLFastTimer::sTimerCycles = 0;
-U32 LLFastTimer::sTimerCalls = 0;
-
-
-// FIXME: move these declarations to the relevant modules
-
-// helper functions
-typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t;
-
-static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id)
-{
- return timer_tree_bottom_up_iterator_t(&id,
- boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
- boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
-}
-
-static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
-{
- return timer_tree_bottom_up_iterator_t();
-}
-
-typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t;
-
-
-static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id)
-{
- return timer_tree_dfs_iterator_t(&id,
- boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
- boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
-}
-
-static timer_tree_dfs_iterator_t end_timer_tree()
-{
- return timer_tree_dfs_iterator_t();
-}
-
-
-
-// factory class that creates NamedTimers via static DeclareTimer objects
-class NamedTimerFactory : public LLSingleton<NamedTimerFactory>
-{
-public:
- NamedTimerFactory()
- : mActiveTimerRoot(NULL),
- mTimerRoot(NULL),
- mAppTimer(NULL),
- mRootFrameState(NULL)
- {}
-
- /*virtual */ void initSingleton()
- {
- mTimerRoot = new LLFastTimer::NamedTimer("root");
-
- mActiveTimerRoot = new LLFastTimer::NamedTimer("Frame");
- mActiveTimerRoot->setCollapsed(false);
-
- mRootFrameState = new LLFastTimer::FrameState(mActiveTimerRoot);
- mRootFrameState->mParent = &mTimerRoot->getFrameState();
- mActiveTimerRoot->setParent(mTimerRoot);
-
- mAppTimer = new LLFastTimer(mRootFrameState);
- }
-
- ~NamedTimerFactory()
- {
- std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer());
-
- delete mAppTimer;
- delete mActiveTimerRoot;
- delete mTimerRoot;
- delete mRootFrameState;
- }
-
- LLFastTimer::NamedTimer& createNamedTimer(const std::string& name)
- {
- timer_map_t::iterator found_it = mTimers.find(name);
- if (found_it != mTimers.end())
- {
- return *found_it->second;
- }
-
- LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name);
- timer->setParent(mTimerRoot);
- mTimers.insert(std::make_pair(name, timer));
-
- return *timer;
- }
-
- LLFastTimer::NamedTimer* getTimerByName(const std::string& name)
- {
- timer_map_t::iterator found_it = mTimers.find(name);
- if (found_it != mTimers.end())
- {
- return found_it->second;
- }
- return NULL;
- }
-
- LLFastTimer::NamedTimer* getActiveRootTimer() { return mActiveTimerRoot; }
- LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; }
- const LLFastTimer* getAppTimer() { return mAppTimer; }
- LLFastTimer::FrameState& getRootFrameState() { return *mRootFrameState; }
-
- typedef std::map<std::string, LLFastTimer::NamedTimer*> timer_map_t;
- timer_map_t::iterator beginTimers() { return mTimers.begin(); }
- timer_map_t::iterator endTimers() { return mTimers.end(); }
- S32 timerCount() { return mTimers.size(); }
-
-private:
- timer_map_t mTimers;
-
- LLFastTimer::NamedTimer* mActiveTimerRoot;
- LLFastTimer::NamedTimer* mTimerRoot;
- LLFastTimer* mAppTimer;
- LLFastTimer::FrameState* mRootFrameState;
-};
-
-void update_cached_pointers_if_changed()
-{
- // detect when elements have moved and update cached pointers
- static LLFastTimer::FrameState* sFirstTimerAddress = NULL;
- if (&*(LLFastTimer::getFrameStateList().begin()) != sFirstTimerAddress)
- {
- LLFastTimer::DeclareTimer::updateCachedPointers();
- }
- sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin());
-}
-
-LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open )
-: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
-{
- mTimer.setCollapsed(!open);
- mFrameState = &mTimer.getFrameState();
- update_cached_pointers_if_changed();
-}
-
-LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
-: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
-{
- mFrameState = &mTimer.getFrameState();
- update_cached_pointers_if_changed();
-}
-
-// static
-void LLFastTimer::DeclareTimer::updateCachedPointers()
-{
- // propagate frame state pointers to timer declarations
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
- {
- // update cached pointer
- it->mFrameState = &it->mTimer.getFrameState();
- }
-
- // also update frame states of timers on stack
- LLFastTimer* cur_timerp = LLFastTimer::sCurTimerData.mCurTimer;
- while(cur_timerp->mLastTimerData.mCurTimer != cur_timerp)
- {
- cur_timerp->mFrameState = &cur_timerp->mFrameState->mTimer->getFrameState();
- cur_timerp = cur_timerp->mLastTimerData.mCurTimer;
- }
-}
-
-//static
-#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
-{
- return sClockResolution >> 8;
-}
-#else // windows or x86-mac or x86-linux or x86-solaris
-U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
-{
-#if USE_RDTSC || !LL_WINDOWS
- //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
- static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
-
- // we drop the low-order byte in our timers, so report a lower frequency
-#else
- // If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
- // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
- // since that would change displayed MHz stats for CPUs
- static bool firstcall = true;
- static U64 sCPUClockFrequency;
- if (firstcall)
- {
- QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
- firstcall = false;
- }
-#endif
- return sCPUClockFrequency >> 8;
-}
-#endif
-
-LLFastTimer::FrameState::FrameState(LLFastTimer::NamedTimer* timerp)
-: mActiveCount(0),
- mCalls(0),
- mSelfTimeCounter(0),
- mParent(NULL),
- mLastCaller(NULL),
- mMoveUpTree(false),
- mTimer(timerp)
-{}
-
-
-LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
-: mName(name),
- mCollapsed(true),
- mParent(NULL),
- mTotalTimeCounter(0),
- mCountAverage(0),
- mCallAverage(0),
- mNeedsSorting(false)
-{
- info_list_t& frame_state_list = getFrameStateList();
- mFrameStateIndex = frame_state_list.size();
- getFrameStateList().push_back(FrameState(this));
-
- mCountHistory = new U32[HISTORY_NUM];
- memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
- mCallHistory = new U32[HISTORY_NUM];
- memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
-}
-
-LLFastTimer::NamedTimer::~NamedTimer()
-{
- delete[] mCountHistory;
- delete[] mCallHistory;
-}
-
-std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
-{
- F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond();
- if (history_idx < 0)
- {
- // by default, show average number of call
- return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getCountAverage() * ms_multiplier), (S32)getCallAverage());
- }
- else
- {
- return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx));
- }
-}
-
-void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
-{
- llassert_always(parent != this);
- llassert_always(parent != NULL);
-
- if (mParent)
- {
- // subtract our accumulated from previous parent
- for (S32 i = 0; i < HISTORY_NUM; i++)
- {
- mParent->mCountHistory[i] -= mCountHistory[i];
- }
-
- // subtract average timing from previous parent
- mParent->mCountAverage -= mCountAverage;
-
- std::vector<NamedTimer*>& children = mParent->getChildren();
- std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
- if (found_it != children.end())
- {
- children.erase(found_it);
- }
- }
-
- mParent = parent;
- if (parent)
- {
- getFrameState().mParent = &parent->getFrameState();
- parent->getChildren().push_back(this);
- parent->mNeedsSorting = true;
- }
-}
-
-S32 LLFastTimer::NamedTimer::getDepth()
-{
- S32 depth = 0;
- NamedTimer* timerp = mParent;
- while(timerp)
- {
- depth++;
- timerp = timerp->mParent;
- }
- return depth;
-}
-
-// static
-void LLFastTimer::NamedTimer::processTimes()
-{
- if (sCurFrameIndex < 0) return;
-
- buildHierarchy();
- accumulateTimings();
-}
-
-// sort timer info structs by depth first traversal order
-struct SortTimersDFS
-{
- bool operator()(const LLFastTimer::FrameState& i1, const LLFastTimer::FrameState& i2)
- {
- return i1.mTimer->getFrameStateIndex() < i2.mTimer->getFrameStateIndex();
- }
-};
-
-// sort child timers by name
-struct SortTimerByName
-{
- bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2)
- {
- return i1->getName() < i2->getName();
- }
-};
-
-//static
-void LLFastTimer::NamedTimer::buildHierarchy()
-{
- if (sCurFrameIndex < 0 ) return;
-
- // set up initial tree
- {
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
- {
- NamedTimer& timer = *it;
- if (&timer == NamedTimerFactory::instance().getRootTimer()) continue;
-
- // bootstrap tree construction by attaching to last timer to be on stack
- // when this timer was called
- if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer())
- {
- timer.setParent(timer.getFrameState().mLastCaller->mTimer);
- // no need to push up tree on first use, flag can be set spuriously
- timer.getFrameState().mMoveUpTree = false;
- }
- }
- }
-
- // bump timers up tree if they've 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(*NamedTimerFactory::instance().getRootTimer());
- it != end_timer_tree_bottom_up();
- ++it)
- {
- NamedTimer* timerp = *it;
- // skip root timer
- if (timerp == NamedTimerFactory::instance().getRootTimer()) continue;
-
- if (timerp->getFrameState().mMoveUpTree)
- {
- // since ancestors have already been visited, reparenting won't affect tree traversal
- //step up tree, bringing our descendants with us
- //llinfos << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
- // " to child of " << timerp->getParent()->getParent()->getName() << llendl;
- timerp->setParent(timerp->getParent()->getParent());
- timerp->getFrameState().mMoveUpTree = false;
-
- // don't bubble up any ancestors until descendants are done bubbling up
- it.skipAncestors();
- }
- }
-
- // sort timers by time last called, so call graph makes sense
- for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
- it != end_timer_tree();
- ++it)
- {
- NamedTimer* timerp = (*it);
- if (timerp->mNeedsSorting)
- {
- std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
- }
- timerp->mNeedsSorting = false;
- }
-}
-
-//static
-void LLFastTimer::NamedTimer::accumulateTimings()
-{
- U32 cur_time = getCPUClockCount32();
-
- // walk up stack of active timers and accumulate current time while leaving timing structures active
- LLFastTimer* cur_timer = sCurTimerData.mCurTimer;
- // root defined by parent pointing to self
- CurTimerData* cur_data = &sCurTimerData;
- while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
- {
- U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
- U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
- cur_data->mChildTime = 0;
- cur_timer->mFrameState->mSelfTimeCounter += self_time_delta;
- cur_timer->mStartTime = cur_time;
-
- cur_data = &cur_timer->mLastTimerData;
- cur_data->mChildTime += cumulative_time_delta;
-
- cur_timer = cur_timer->mLastTimerData.mCurTimer;
- }
-
- // traverse tree in DFS post order, or bottom up
- for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getActiveRootTimer());
- it != end_timer_tree_bottom_up();
- ++it)
- {
- NamedTimer* timerp = (*it);
- timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter;
- for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
- {
- timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter;
- }
-
- S32 cur_frame = sCurFrameIndex;
- if (cur_frame >= 0)
- {
- // update timer history
- int hidx = cur_frame % HISTORY_NUM;
-
- timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter;
- timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
- timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
- timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
- }
- }
-}
-
-// static
-void LLFastTimer::NamedTimer::resetFrame()
-{
- if (sLog)
- { //output current frame counts to performance log
-
- static S32 call_count = 0;
- if (call_count % 100 == 0)
- {
- llinfos << "countsPerSecond (32 bit): " << countsPerSecond() << llendl;
- llinfos << "get_clock_count (64 bit): " << get_clock_count() << llendl;
- llinfos << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << llendl;
- llinfos << "getCPUClockCount32() " << getCPUClockCount32() << llendl;
- llinfos << "getCPUClockCount64() " << getCPUClockCount64() << llendl;
- llinfos << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << llendl;
- }
- call_count++;
-
- F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
-
- F64 total_time = 0;
- LLSD sd;
-
- {
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
- {
- NamedTimer& timer = *it;
- FrameState& info = timer.getFrameState();
- sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq);
- sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls;
-
- // computing total time here because getting the root timer's getCountHistory
- // doesn't work correctly on the first frame
- total_time = total_time + info.mSelfTimeCounter * iclock_freq;
- }
- }
-
- sd["Total"]["Time"] = (LLSD::Real) total_time;
- sd["Total"]["Calls"] = (LLSD::Integer) 1;
-
- {
- LLMutexLock lock(sLogLock);
- sLogQueue.push(sd);
- }
- }
-
-
- // tag timers by position in depth first traversal of tree
- S32 index = 0;
- for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
- it != end_timer_tree();
- ++it)
- {
- NamedTimer* timerp = (*it);
-
- timerp->mFrameStateIndex = index;
- index++;
-
- llassert_always(timerp->mFrameStateIndex < (S32)getFrameStateList().size());
- }
-
- // sort timers by DFS traversal order to improve cache coherency
- std::sort(getFrameStateList().begin(), getFrameStateList().end(), SortTimersDFS());
-
- // update pointers into framestatelist now that we've sorted it
- DeclareTimer::updateCachedPointers();
-
- // reset for next frame
- {
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
- {
- NamedTimer& timer = *it;
-
- FrameState& info = timer.getFrameState();
- info.mSelfTimeCounter = 0;
- info.mCalls = 0;
- info.mLastCaller = NULL;
- info.mMoveUpTree = false;
- // update parent pointer in timer state struct
- if (timer.mParent)
- {
- info.mParent = &timer.mParent->getFrameState();
- }
- }
- }
-
- //sTimerCycles = 0;
- //sTimerCalls = 0;
-}
-
-//static
-void LLFastTimer::NamedTimer::reset()
-{
- resetFrame(); // reset frame data
-
- // walk up stack of active timers and reset start times to current time
- // effectively zeroing out any accumulated time
- U32 cur_time = getCPUClockCount32();
-
- // root defined by parent pointing to self
- CurTimerData* cur_data = &sCurTimerData;
- LLFastTimer* cur_timer = cur_data->mCurTimer;
- while(cur_timer->mLastTimerData.mCurTimer != cur_timer)
- {
- cur_timer->mStartTime = cur_time;
- cur_data->mChildTime = 0;
-
- cur_data = &cur_timer->mLastTimerData;
- cur_timer = cur_data->mCurTimer;
- }
-
- // reset all history
- {
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
- {
- NamedTimer& timer = *it;
- if (&timer != NamedTimerFactory::instance().getRootTimer())
- {
- timer.setParent(NamedTimerFactory::instance().getRootTimer());
- }
-
- timer.mCountAverage = 0;
- timer.mCallAverage = 0;
- memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
- memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
- }
- }
-
- sLastFrameIndex = 0;
- sCurFrameIndex = 0;
-}
-
-//static
-LLFastTimer::info_list_t& LLFastTimer::getFrameStateList()
-{
- if (!sTimerInfos)
- {
- sTimerInfos = new info_list_t();
- }
- return *sTimerInfos;
-}
-
-
-U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const
-{
- S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
- return mCountHistory[history_idx];
-}
-
-U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const
-{
- S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
- return mCallHistory[history_idx];
-}
-
-LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const
-{
- llassert_always(mFrameStateIndex >= 0);
- if (this == NamedTimerFactory::instance().getActiveRootTimer())
- {
- return NamedTimerFactory::instance().getRootFrameState();
- }
- return getFrameStateList()[mFrameStateIndex];
-}
-
-// static
-LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer()
-{
- return *NamedTimerFactory::instance().getActiveRootTimer();
-}
-
-std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren()
-{
- return mChildren.begin();
-}
-
-std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren()
-{
- return mChildren.end();
-}
-
-std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
-{
- return mChildren;
-}
-
-//static
-void LLFastTimer::nextFrame()
-{
- countsPerSecond(); // good place to calculate clock frequency
- U64 frame_time = getCPUClockCount64();
- if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff)
- {
- llinfos << "Slow frame, fast timers inaccurate" << llendl;
- }
-
- if (!sPauseHistory)
- {
- NamedTimer::processTimes();
- sLastFrameIndex = sCurFrameIndex++;
- }
-
- // get ready for next frame
- NamedTimer::resetFrame();
- sLastFrameTime = frame_time;
-}
-
-//static
-void LLFastTimer::dumpCurTimes()
-{
- // accumulate timings, etc.
- NamedTimer::processTimes();
-
- F64 clock_freq = (F64)countsPerSecond();
- F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds
-
- // walk over timers in depth order and output timings
- for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
- it != end_timer_tree();
- ++it)
- {
- NamedTimer* timerp = (*it);
- F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
- // Don't bother with really brief times, keep output concise
- if (total_time_ms < 0.1) continue;
-
- std::ostringstream out_str;
- for (S32 i = 0; i < timerp->getDepth(); i++)
- {
- out_str << "\t";
- }
-
-
- out_str << timerp->getName() << " "
- << std::setprecision(3) << total_time_ms << " ms, "
- << timerp->getHistoricalCalls(0) << " calls";
-
- llinfos << out_str.str() << llendl;
- }
-}
-
-//static
-void LLFastTimer::reset()
-{
- NamedTimer::reset();
-}
-
-
-//static
-void LLFastTimer::writeLog(std::ostream& os)
-{
- while (!sLogQueue.empty())
- {
- LLSD& sd = sLogQueue.front();
- LLSDSerialize::toXML(sd, os);
- LLMutexLock lock(sLogLock);
- sLogQueue.pop();
- }
-}
-
-//static
-const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name)
-{
- return NamedTimerFactory::instance().getTimerByName(name);
-}
-
-LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
-: mFrameState(state)
-{
- U32 start_time = getCPUClockCount32();
- mStartTime = start_time;
- mFrameState->mActiveCount++;
- LLFastTimer::sCurTimerData.mCurTimer = this;
- LLFastTimer::sCurTimerData.mFrameState = mFrameState;
- LLFastTimer::sCurTimerData.mChildTime = 0;
- mLastTimerData = LLFastTimer::sCurTimerData;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// Important note: These implementations must be FAST!
-//
-
-
-#if LL_WINDOWS
-//
-// Windows implementation of CPU clock
-//
-
-//
-// NOTE: put back in when we aren't using platform sdk anymore
-//
-// because MS has different signatures for these functions in winnt.h
-// need to rename them to avoid conflicts
-//#define _interlockedbittestandset _renamed_interlockedbittestandset
-//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
-//#include <intrin.h>
-//#undef _interlockedbittestandset
-//#undef _interlockedbittestandreset
-
-//inline U32 LLFastTimer::getCPUClockCount32()
-//{
-// U64 time_stamp = __rdtsc();
-// return (U32)(time_stamp >> 8);
-//}
-//
-//// return full timer value, *not* shifted by 8 bits
-//inline U64 LLFastTimer::getCPUClockCount64()
-//{
-// return __rdtsc();
-//}
-
-// shift off lower 8 bits for lower resolution but longer term timing
-// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
-#if USE_RDTSC
-U32 LLFastTimer::getCPUClockCount32()
-{
- U32 ret_val;
- __asm
- {
- _emit 0x0f
- _emit 0x31
- shr eax,8
- shl edx,24
- or eax, edx
- mov dword ptr [ret_val], eax
- }
- return ret_val;
-}
-
-// return full timer value, *not* shifted by 8 bits
-U64 LLFastTimer::getCPUClockCount64()
-{
- U64 ret_val;
- __asm
- {
- _emit 0x0f
- _emit 0x31
- mov eax,eax
- mov edx,edx
- mov dword ptr [ret_val+4], edx
- mov dword ptr [ret_val], eax
- }
- return ret_val;
-}
-
-std::string LLFastTimer::sClockType = "rdtsc";
-
-#else
-//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
-// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
-U32 LLFastTimer::getCPUClockCount32()
-{
- return (U32)(get_clock_count()>>8);
-}
-
-U64 LLFastTimer::getCPUClockCount64()
-{
- return get_clock_count();
-}
-
-std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
-#endif
-
-#endif
-
-
-#if (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-//
-// Linux and Solaris implementation of CPU clock - non-x86.
-// This is accurate but SLOW! Only use out of desperation.
-//
-// Try to use the MONOTONIC clock if available, this is a constant time counter
-// with nanosecond resolution (but not necessarily accuracy) and attempts are
-// made to synchronize this value between cores at kernel start. It should not
-// be affected by CPU frequency. If not available use the REALTIME clock, but
-// this may be affected by NTP adjustments or other user activity affecting
-// the system time.
-U64 LLFastTimer::getCPUClockCount64()
-{
- struct timespec tp;
-
-#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
- if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
-#endif
- clock_gettime(CLOCK_REALTIME,&tp);
-
- return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
-}
-
-U32 LLFastTimer::getCPUClockCount32()
-{
- return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
-}
-
-std::string LLFastTimer::sClockType = "clock_gettime";
-
-#endif // (LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-
-
-#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
-//
-// Mac+Linux+Solaris FAST x86 implementation of CPU clock
-U32 LLFastTimer::getCPUClockCount32()
-{
- U64 x;
- __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return (U32)(x >> 8);
-}
-
-U64 LLFastTimer::getCPUClockCount64()
-{
- U64 x;
- __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return x;
-}
-
-std::string LLFastTimer::sClockType = "rdtsc";
-#endif
-
diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h
deleted file mode 100644
index f481e968a6..0000000000
--- a/indra/llcommon/llfasttimer_class.h
+++ /dev/null
@@ -1,276 +0,0 @@
-/**
- * @file llfasttimer_class.h
- * @brief Declaration of a fast timer.
- *
- * $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_FASTTIMER_CLASS_H
-#define LL_FASTTIMER_CLASS_H
-
-#include "llinstancetracker.h"
-
-#define FAST_TIMER_ON 1
-#define TIME_FAST_TIMERS 0
-#define DEBUG_FAST_TIMER_THREADS 1
-
-class LLMutex;
-
-#include <queue>
-#include "llsd.h"
-
-LL_COMMON_API void assert_main_thread();
-
-class LL_COMMON_API LLFastTimer
-{
-public:
- class NamedTimer;
-
- struct LL_COMMON_API FrameState
- {
- FrameState(NamedTimer* timerp);
-
- U32 mSelfTimeCounter;
- U32 mCalls;
- FrameState* mParent; // info for caller timer
- FrameState* mLastCaller; // used to bootstrap tree construction
- NamedTimer* mTimer;
- U16 mActiveCount; // number of timers with this ID active on stack
- bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
- };
-
- // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
- class LL_COMMON_API NamedTimer
- : public LLInstanceTracker<NamedTimer>
- {
- friend class DeclareTimer;
- public:
- ~NamedTimer();
-
- enum { HISTORY_NUM = 300 };
-
- const std::string& getName() const { return mName; }
- NamedTimer* getParent() const { return mParent; }
- void setParent(NamedTimer* parent);
- S32 getDepth();
- std::string getToolTip(S32 history_index = -1);
-
- typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
- child_const_iter beginChildren();
- child_const_iter endChildren();
- std::vector<NamedTimer*>& getChildren();
-
- void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
- bool getCollapsed() const { return mCollapsed; }
-
- U32 getCountAverage() const { return mCountAverage; }
- U32 getCallAverage() const { return mCallAverage; }
-
- U32 getHistoricalCount(S32 history_index = 0) const;
- U32 getHistoricalCalls(S32 history_index = 0) const;
-
- static NamedTimer& getRootNamedTimer();
-
- S32 getFrameStateIndex() const { return mFrameStateIndex; }
-
- FrameState& getFrameState() const;
-
- private:
- friend class LLFastTimer;
- friend class NamedTimerFactory;
-
- //
- // methods
- //
- NamedTimer(const std::string& name);
- // recursive call to gather total time from children
- static void accumulateTimings();
-
- // updates cumulative times and hierarchy,
- // can be called multiple times in a frame, at any point
- static void processTimes();
-
- static void buildHierarchy();
- static void resetFrame();
- static void reset();
-
- //
- // members
- //
- S32 mFrameStateIndex;
-
- std::string mName;
-
- U32 mTotalTimeCounter;
-
- U32 mCountAverage;
- U32 mCallAverage;
-
- U32* mCountHistory;
- U32* mCallHistory;
-
- // tree structure
- NamedTimer* mParent; // NamedTimer of caller(parent)
- std::vector<NamedTimer*> mChildren;
- bool mCollapsed; // don't show children
- bool mNeedsSorting; // sort children whenever child added
- };
-
- // used to statically declare a new named timer
- class LL_COMMON_API DeclareTimer
- : public LLInstanceTracker<DeclareTimer>
- {
- friend class LLFastTimer;
- public:
- DeclareTimer(const std::string& name, bool open);
- DeclareTimer(const std::string& name);
-
- static void updateCachedPointers();
-
- private:
- NamedTimer& mTimer;
- FrameState* mFrameState;
- };
-
-public:
- LLFastTimer(LLFastTimer::FrameState* state);
-
- LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
- : mFrameState(timer.mFrameState)
- {
-#if TIME_FAST_TIMERS
- U64 timer_start = getCPUClockCount64();
-#endif
-#if FAST_TIMER_ON
- LLFastTimer::FrameState* frame_state = mFrameState;
- mStartTime = getCPUClockCount32();
-
- frame_state->mActiveCount++;
- frame_state->mCalls++;
- // keep current parent as long as it is active when we are
- frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
-
- LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData;
- mLastTimerData = *cur_timer_data;
- cur_timer_data->mCurTimer = this;
- cur_timer_data->mFrameState = frame_state;
- cur_timer_data->mChildTime = 0;
-#endif
-#if TIME_FAST_TIMERS
- U64 timer_end = getCPUClockCount64();
- sTimerCycles += timer_end - timer_start;
-#endif
-#if DEBUG_FAST_TIMER_THREADS
-#if !LL_RELEASE
- assert_main_thread();
-#endif
-#endif
- }
-
- LL_FORCE_INLINE ~LLFastTimer()
- {
-#if TIME_FAST_TIMERS
- U64 timer_start = getCPUClockCount64();
-#endif
-#if FAST_TIMER_ON
- LLFastTimer::FrameState* frame_state = mFrameState;
- U32 total_time = getCPUClockCount32() - mStartTime;
-
- frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
- frame_state->mActiveCount--;
-
- // store last caller to bootstrap tree creation
- // do this in the destructor in case of recursion to get topmost caller
- frame_state->mLastCaller = mLastTimerData.mFrameState;
-
- // we are only tracking self time, so subtract our total time delta from parents
- mLastTimerData.mChildTime += total_time;
-
- LLFastTimer::sCurTimerData = mLastTimerData;
-#endif
-#if TIME_FAST_TIMERS
- U64 timer_end = getCPUClockCount64();
- sTimerCycles += timer_end - timer_start;
- sTimerCalls++;
-#endif
- }
-
-public:
- static LLMutex* sLogLock;
- static std::queue<LLSD> sLogQueue;
- static BOOL sLog;
- static BOOL sMetricLog;
- static std::string sLogName;
- static bool sPauseHistory;
- static bool sResetHistory;
- static U64 sTimerCycles;
- static U32 sTimerCalls;
-
- typedef std::vector<FrameState> info_list_t;
- static info_list_t& getFrameStateList();
-
-
- // call this once a frame to reset timers
- static void nextFrame();
-
- // dumps current cumulative frame stats to log
- // call nextFrame() to reset timers
- static void dumpCurTimes();
-
- // call this to reset timer hierarchy, averages, etc.
- static void reset();
-
- static U64 countsPerSecond();
- static S32 getLastFrameIndex() { return sLastFrameIndex; }
- static S32 getCurFrameIndex() { return sCurFrameIndex; }
-
- static void writeLog(std::ostream& os);
- static const NamedTimer* getTimerByName(const std::string& name);
-
- struct CurTimerData
- {
- LLFastTimer* mCurTimer;
- FrameState* mFrameState;
- U32 mChildTime;
- };
- static CurTimerData sCurTimerData;
- static std::string sClockType;
-
-private:
- static U32 getCPUClockCount32();
- static U64 getCPUClockCount64();
- static U64 sClockResolution;
-
- static S32 sCurFrameIndex;
- static S32 sLastFrameIndex;
- static U64 sLastFrameTime;
- static info_list_t* sTimerInfos;
-
- U32 mStartTime;
- LLFastTimer::FrameState* mFrameState;
- LLFastTimer::CurTimerData mLastTimerData;
-
-};
-
-typedef class LLFastTimer LLFastTimer;
-
-#endif // LL_LLFASTTIMER_CLASS_H
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index c51d042a3d..5917d7a420 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -28,7 +28,7 @@
*/
#if LL_WINDOWS
-#include <windows.h>
+#include "llwin32headerslean.h"
#include <stdlib.h> // Windows errno
#else
#include <errno.h>
diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp
index cd7c0c7c09..f019bd0c64 100644
--- a/indra/llcommon/llfindlocale.cpp
+++ b/indra/llcommon/llfindlocale.cpp
@@ -33,7 +33,7 @@
#include <ctype.h>
#ifdef WIN32
-#include <windows.h>
+#include "llwin32headers.h"
#include <winnt.h>
#endif
diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp
index db72aa19b9..d72e10d2fa 100644
--- a/indra/llcommon/llinitparam.cpp
+++ b/indra/llcommon/llinitparam.cpp
@@ -28,10 +28,17 @@
#include "linden_common.h"
#include "llinitparam.h"
+#include "llformat.h"
namespace LLInitParam
{
+
+ predicate_rule_t default_parse_rules()
+ {
+ return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY);
+ }
+
//
// Param
//
@@ -164,6 +171,9 @@ namespace LLInitParam
bool BaseBlock::validateBlock(bool emit_errors) const
{
+ // only validate block when it hasn't already passed validation with current data
+ if (!mValidated)
+ {
const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it)
{
@@ -177,11 +187,18 @@ namespace LLInitParam
return false;
}
}
- return true;
+ mValidated = true;
+ }
+ return mValidated;
}
- void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const
+ bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const
{
+ bool serialized = false;
+ if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided())))
+ {
+ return false;
+ }
// named param is one like LLView::Params::follows
// unnamed param is like LLView::Params::rect - implicit
const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
@@ -193,15 +210,10 @@ namespace LLInitParam
param_handle_t param_handle = (*it)->mParamHandle;
const Param* param = getParamFromHandle(param_handle);
ParamDescriptor::serialize_func_t serialize_func = (*it)->mSerializeFunc;
- if (serialize_func)
+ if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided())))
{
const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
- // each param descriptor remembers its serial number
- // so we can inspect the same param under different names
- // and see that it has the same number
- name_stack.push_back(std::make_pair("", true));
- serialize_func(*param, parser, name_stack, diff_param);
- name_stack.pop_back();
+ serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param);
}
}
@@ -212,7 +224,7 @@ namespace LLInitParam
param_handle_t param_handle = it->second->mParamHandle;
const Param* param = getParamFromHandle(param_handle);
ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc;
- if (serialize_func && param->anyProvided())
+ if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided())))
{
// Ensure this param has not already been serialized
// Prevents <rect> from being serialized as its own tag.
@@ -237,10 +249,17 @@ namespace LLInitParam
name_stack.push_back(std::make_pair(it->first, !duplicate));
const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
- serialize_func(*param, parser, name_stack, diff_param);
+ serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param);
name_stack.pop_back();
}
}
+
+ if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
+ {
+ serialized |= parser.writeValue(Flag(), name_stack);
+ }
+ // was anything serialized in this block?
+ return serialized;
}
bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const
@@ -359,7 +378,7 @@ namespace LLInitParam
}
//static
- void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name)
+ void BaseBlock::addParam(BlockDescriptor& block_data, ParamDescriptorPtr in_param, const char* char_name)
{
// create a copy of the param descriptor in mAllParams
// so other data structures can store a pointer to it
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index 9a6d1eff5c..502f93cbb8 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -29,13 +29,14 @@
#define LL_LLPARAM_H
#include <vector>
+#include <list>
#include <boost/function.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/unordered_map.hpp>
-#include <boost/shared_ptr.hpp>
#include "llerror.h"
#include "llstl.h"
+#include "llpredicate.h"
namespace LLInitParam
{
@@ -211,7 +212,6 @@ namespace LLInitParam
LOG_CLASS(Parser);
public:
-
typedef std::vector<std::pair<std::string, bool> > name_stack_t;
typedef std::pair<name_stack_t::iterator, name_stack_t::iterator> name_stack_range_t;
typedef std::vector<std::string> possible_values_t;
@@ -293,6 +293,19 @@ namespace LLInitParam
class Param;
+ enum ESerializePredicates
+ {
+ PROVIDED,
+ REQUIRED,
+ VALID,
+ HAS_DEFAULT_VALUE,
+ EMPTY
+ };
+
+ typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t;
+
+ predicate_rule_t default_parse_rules();
+
// various callbacks and constraints associated with an individual param
struct LL_COMMON_API ParamDescriptor
{
@@ -303,8 +316,8 @@ namespace LLInitParam
typedef bool(*merge_func_t)(Param&, const Param&, bool);
typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool);
- typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);
- typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count);
+ typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t, const Param*);
+ typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32, S32);
typedef bool(*validation_func_t)(const Param*);
ParamDescriptor(param_handle_t p,
@@ -331,7 +344,7 @@ namespace LLInitParam
UserData* mUserData;
};
- typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
+ typedef ParamDescriptor* ParamDescriptorPtr;
// each derived Block class keeps a static data structure maintaining offsets to various params
class LL_COMMON_API BlockDescriptor
@@ -484,12 +497,28 @@ namespace LLInitParam
LOG_CLASS(BaseBlock);
friend class Param;
+ BaseBlock()
+ : mValidated(false),
+ mParamProvided(false)
+ {}
+
virtual ~BaseBlock() {}
bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false);
param_handle_t getHandleFromParam(const Param* param) const;
bool validateBlock(bool emit_errors = true) const;
+ bool isProvided() const
+ {
+ return mParamProvided;
+ }
+
+ bool isValid() const
+ {
+ return validateBlock(false);
+ }
+
+
Param* getParamFromHandle(const param_handle_t param_handle)
{
if (param_handle == 0) return NULL;
@@ -507,10 +536,19 @@ namespace LLInitParam
void addSynonym(Param& param, const std::string& synonym);
// Blocks can override this to do custom tracking of changes
- virtual void paramChanged(const Param& changed_param, bool user_provided) {}
+ virtual void paramChanged(const Param& changed_param, bool user_provided)
+ {
+ if (user_provided)
+ {
+ // a child param has been explicitly changed
+ // so *some* aspect of this block is now provided
+ mValidated = false;
+ mParamProvided = true;
+ }
+ }
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
- void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
+ bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const;
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const;
virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
@@ -549,6 +587,9 @@ namespace LLInitParam
return sBlockDescriptor;
}
+ mutable bool mValidated; // lazy validation flag
+ bool mParamProvided;
+
private:
const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
};
@@ -688,13 +729,11 @@ namespace LLInitParam
typedef ParamValue<T, NAME_VALUE_LOOKUP, true> self_t;
ParamValue()
- : T(),
- mValidated(false)
+ : T()
{}
ParamValue(value_assignment_t other)
- : T(other),
- mValidated(false)
+ : T(other)
{}
void setValue(value_assignment_t val)
@@ -736,9 +775,6 @@ namespace LLInitParam
return *this;
}
-
- protected:
- mutable bool mValidated; // lazy validation flag
};
template<typename NAME_VALUE_LOOKUP>
@@ -836,6 +872,8 @@ namespace LLInitParam
bool isProvided() const { return Param::anyProvided(); }
+ bool isValid() const { return true; }
+
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
{
self_t& typed_param = static_cast<self_t&>(param);
@@ -870,10 +908,23 @@ namespace LLInitParam
return false;
}
- static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+ static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
{
+ bool serialized = false;
const self_t& typed_param = static_cast<const self_t&>(param);
- if (!typed_param.isProvided()) return;
+ const self_t* diff_typed_param = static_cast<const self_t*>(diff_param);
+
+ LLPredicate::Value<ESerializePredicates> predicate;
+ if (diff_typed_param && ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue()))
+ {
+ predicate.set(HAS_DEFAULT_VALUE);
+ }
+
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+ predicate.set(EMPTY, false);
+
+ if (!predicate_rule.check(predicate)) return false;
if (!name_stack.empty())
{
@@ -886,23 +937,25 @@ namespace LLInitParam
if (!key.empty())
{
- if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
+ if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key))
{
- parser.writeValue(key, name_stack);
+ serialized = parser.writeValue(key, name_stack);
}
}
// then try to serialize value directly
- else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), static_cast<const self_t*>(diff_param)->getValue()))
+ else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue()))
{
- if (!parser.writeValue(typed_param.getValue(), name_stack))
+ serialized = parser.writeValue(typed_param.getValue(), name_stack);
+ if (!serialized)
{
std::string calculated_key = typed_param.calcValueName(typed_param.getValue());
- if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))
+ if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), calculated_key))
{
- parser.writeValue(calculated_key, name_stack);
+ serialized = parser.writeValue(calculated_key, name_stack);
}
}
}
+ return serialized;
}
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
@@ -953,15 +1006,15 @@ namespace LLInitParam
};
// parameter that is a block
- template <typename T, typename NAME_VALUE_LOOKUP>
- class TypedParam<T, NAME_VALUE_LOOKUP, false, true>
+ template <typename BLOCK_T, typename NAME_VALUE_LOOKUP>
+ class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, true>
: public Param,
- public ParamValue<T, NAME_VALUE_LOOKUP>
+ public ParamValue<BLOCK_T, NAME_VALUE_LOOKUP>
{
public:
- typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
+ typedef ParamValue<BLOCK_T, NAME_VALUE_LOOKUP> param_value_t;
typedef typename param_value_t::value_assignment_t value_assignment_t;
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false, true> self_t;
+ typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, true> self_t;
typedef NAME_VALUE_LOOKUP name_value_lookup_t;
using param_value_t::operator();
@@ -1014,10 +1067,16 @@ namespace LLInitParam
return false;
}
- static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+ static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
{
const self_t& typed_param = static_cast<const self_t&>(param);
- if (!typed_param.isProvided()) return;
+
+ LLPredicate::Value<ESerializePredicates> predicate;
+
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+
+ if (!predicate_rule.check(predicate)) return false;
if (!name_stack.empty())
{
@@ -1027,15 +1086,17 @@ namespace LLInitParam
std::string key = typed_param.getValueName();
if (!key.empty())
{
- if (!parser.writeValue(key, name_stack))
+ if (parser.writeValue(key, name_stack))
{
- return;
+ return true;
}
}
else
{
- typed_param.serializeBlock(parser, name_stack, static_cast<const self_t*>(diff_param));
+ return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param));
}
+
+ return false;
}
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
@@ -1049,23 +1110,16 @@ namespace LLInitParam
// *and* the block as a whole validates
bool isProvided() const
{
- // only validate block when it hasn't already passed validation with current data
- if (Param::anyProvided() && !param_value_t::mValidated)
- {
- // a sub-block is "provided" when it has been filled in enough to be valid
- param_value_t::mValidated = param_value_t::validateBlock(false);
- }
- return Param::anyProvided() && param_value_t::mValidated;
+ return Param::anyProvided() && isValid();
}
+ using param_value_t::isValid;
+
// assign block contents to this param-that-is-a-block
void set(value_assignment_t val, bool flag_as_provided = true)
{
setValue(val);
param_value_t::clearValueName();
- // force revalidation of block
- // next call to isProvided() will update provision status based on validity
- param_value_t::mValidated = false;
setProvided(flag_as_provided);
}
@@ -1080,9 +1134,6 @@ namespace LLInitParam
param_value_t::paramChanged(changed_param, user_provided);
if (user_provided)
{
- // a child param has been explicitly changed
- // so *some* aspect of this block is now provided
- param_value_t::mValidated = false;
setProvided();
param_value_t::clearValueName();
}
@@ -1120,13 +1171,13 @@ namespace LLInitParam
};
// container of non-block parameters
- template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
- class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false>
+ template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP>
+ class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, false>
: public Param
{
public:
- typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false> self_t;
- typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
+ typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, false> self_t;
+ typedef ParamValue<MULTI_VALUE_T, NAME_VALUE_LOOKUP> param_value_t;
typedef typename std::vector<param_value_t> container_t;
typedef const container_t& value_assignment_t;
@@ -1134,7 +1185,9 @@ namespace LLInitParam
typedef NAME_VALUE_LOOKUP name_value_lookup_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
- : Param(block_descriptor.mCurrentBlockPtr)
+ : Param(block_descriptor.mCurrentBlockPtr),
+ mMinCount(min_count),
+ mMaxCount(max_count)
{
std::copy(value.begin(), value.end(), std::back_inserter(mValues));
@@ -1152,14 +1205,28 @@ namespace LLInitParam
}
}
- bool isProvided() const { return Param::anyProvided(); }
+ bool isProvided() const { return Param::anyProvided() && isValid(); }
+
+ bool isValid() const
+ {
+ size_t num_elements = numValidElements();
+ return mMinCount < num_elements && num_elements < mMaxCount;
+ }
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
{
+ Parser::name_stack_range_t new_name_stack_range(name_stack_range);
self_t& typed_param = static_cast<self_t&>(param);
value_t value;
+
+ // pop first element if empty string
+ if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
+ {
+ ++new_name_stack_range.first;
+ }
+
// no further names in stack, attempt to parse value now
- if (name_stack_range.first == name_stack_range.second)
+ if (new_name_stack_range.first == new_name_stack_range.second)
{
// attempt to read value directly
if (parser.readValue(value))
@@ -1189,17 +1256,26 @@ namespace LLInitParam
return false;
}
- static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+ static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
{
+ bool serialized = false;
const self_t& typed_param = static_cast<const self_t&>(param);
- if (!typed_param.isProvided() || name_stack.empty()) return;
+
+ LLPredicate::Value<ESerializePredicates> predicate;
+
+ predicate.set(REQUIRED, typed_param.mMinCount > 0);
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+ predicate.set(EMPTY, typed_param.mValues.empty());
+
+ if (!predicate_rule.check(predicate)) return false;
for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
it != end_it;
++it)
{
std::string key = it->getValueName();
- name_stack.back().second = true;
+ name_stack.push_back(std::make_pair(std::string(), true));
if(key.empty())
// not parsed via name values, write out value directly
@@ -1208,7 +1284,11 @@ namespace LLInitParam
if (!value_written)
{
std::string calculated_key = it->calcValueName(it->getValue());
- if (!parser.writeValue(calculated_key, name_stack))
+ if (parser.writeValue(calculated_key, name_stack))
+ {
+ serialized = true;
+ }
+ else
{
break;
}
@@ -1216,17 +1296,30 @@ namespace LLInitParam
}
else
{
- if(!parser.writeValue(key, name_stack))
+ if(parser.writeValue(key, name_stack))
+ {
+ serialized = true;
+ }
+ else
{
break;
}
}
+
+ name_stack.pop_back();
+ }
+
+ if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
+ {
+ serialized |= parser.writeValue(Flag(), name_stack);
}
+
+ return serialized;
}
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
{
- parser.inspectValue<VALUE_TYPE>(name_stack, min_count, max_count, NULL);
+ parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL);
if (name_value_lookup_t::getPossibleValues())
{
parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues());
@@ -1283,7 +1376,7 @@ namespace LLInitParam
bool empty() const { return mValues.empty(); }
size_t size() const { return mValues.size(); }
- U32 numValidElements() const
+ size_t numValidElements() const
{
return mValues.size();
}
@@ -1313,23 +1406,27 @@ namespace LLInitParam
}
container_t mValues;
+ size_t mMinCount,
+ mMaxCount;
};
// container of block parameters
- template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
- class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true>
+ template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP>
+ class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, true>
: public Param
{
public:
- typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true> self_t;
- typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
+ typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, true> self_t;
+ typedef ParamValue<MULTI_BLOCK_T, NAME_VALUE_LOOKUP> param_value_t;
typedef typename std::vector<param_value_t> container_t;
typedef const container_t& value_assignment_t;
typedef typename param_value_t::value_t value_t;
typedef NAME_VALUE_LOOKUP name_value_lookup_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
- : Param(block_descriptor.mCurrentBlockPtr)
+ : Param(block_descriptor.mCurrentBlockPtr),
+ mMinCount(min_count),
+ mMaxCount(max_count)
{
std::copy(value.begin(), value.end(), back_inserter(mValues));
@@ -1347,14 +1444,30 @@ namespace LLInitParam
}
}
- bool isProvided() const { return Param::anyProvided(); }
+ bool isProvided() const { return Param::anyProvided() && isValid(); }
+
+ bool isValid() const
+ {
+ size_t num_elements = numValidElements();
+ return mMinCount < num_elements && num_elements < mMaxCount;
+ }
+
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
{
+ Parser::name_stack_range_t new_name_stack_range(name_stack_range);
self_t& typed_param = static_cast<self_t&>(param);
bool new_value = false;
+ bool new_array_value = false;
+
+ // pop first element if empty string
+ if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
+ {
+ new_array_value = new_name_stack_range.first->second;
+ ++new_name_stack_range.first;
+ }
- if (new_name || typed_param.mValues.empty())
+ if (new_name || new_array_value || typed_param.mValues.empty())
{
new_value = true;
typed_param.mValues.push_back(value_t());
@@ -1363,9 +1476,13 @@ namespace LLInitParam
param_value_t& value = typed_param.mValues.back();
// attempt to parse block...
- if(value.deserializeBlock(parser, name_stack_range, new_name))
+ if(value.deserializeBlock(parser, new_name_stack_range, new_name))
{
typed_param.setProvided();
+ if (new_array_value)
+ {
+ name_stack_range.first->second = false;
+ }
return true;
}
else if(name_value_lookup_t::valueNamesExist())
@@ -1379,6 +1496,10 @@ namespace LLInitParam
{
typed_param.mValues.back().setValueName(name);
typed_param.setProvided();
+ if (new_array_value)
+ {
+ name_stack_range.first->second = false;
+ }
return true;
}
@@ -1393,29 +1514,47 @@ namespace LLInitParam
return false;
}
- static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+ static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
{
+ bool serialized = false;
const self_t& typed_param = static_cast<const self_t&>(param);
- if (!typed_param.isProvided() || name_stack.empty()) return;
+
+ LLPredicate::Value<ESerializePredicates> predicate;
+
+ predicate.set(REQUIRED, typed_param.mMinCount > 0);
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+ predicate.set(EMPTY, typed_param.mValues.empty());
+
+ if (!predicate_rule.check(predicate)) return false;
for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
it != end_it;
++it)
{
- name_stack.back().second = true;
+ name_stack.push_back(std::make_pair(std::string(), true));
std::string key = it->getValueName();
if (!key.empty())
{
- parser.writeValue(key, name_stack);
+ serialized |= parser.writeValue(key, name_stack);
}
// Not parsed via named values, write out value directly
- // NOTE: currently we don't worry about removing default values in Multiple
+ // NOTE: currently we don't do diffing of Multiples
else
{
- it->serializeBlock(parser, name_stack, NULL);
+ serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL);
}
+
+ name_stack.pop_back();
}
+
+ if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
+ {
+ serialized |= parser.writeValue(Flag(), name_stack);
+ }
+
+ return serialized;
}
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
@@ -1471,14 +1610,14 @@ namespace LLInitParam
bool empty() const { return mValues.empty(); }
size_t size() const { return mValues.size(); }
- U32 numValidElements() const
+ size_t numValidElements() const
{
- U32 count = 0;
+ size_t count = 0;
for (const_iterator it = mValues.begin(), end_it = mValues.end();
it != end_it;
++it)
{
- if(it->validateBlock(false)) count++;
+ if(it->isValid()) count++;
}
return count;
}
@@ -1510,6 +1649,8 @@ namespace LLInitParam
}
container_t mValues;
+ size_t mMinCount,
+ mMaxCount;
};
template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
@@ -1797,7 +1938,7 @@ namespace LLInitParam
static bool validate(const Param* paramp)
{
- U32 num_valid = ((super_t*)paramp)->numValidElements();
+ size_t num_valid = ((super_t*)paramp)->numValidElements();
return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount;
}
};
@@ -1914,13 +2055,11 @@ namespace LLInitParam
typedef block_t value_t;
ParamValue()
- : block_t(),
- mValidated(false)
+ : block_t()
{}
ParamValue(value_assignment_t other)
- : block_t(other),
- mValidated(false)
+ : block_t(other)
{
}
@@ -1948,9 +2087,6 @@ namespace LLInitParam
{
return *this;
}
-
- protected:
- mutable bool mValidated; // lazy validation flag
};
template<typename T, bool IS_BLOCK>
@@ -1965,13 +2101,11 @@ namespace LLInitParam
typedef T value_t;
ParamValue()
- : mValue(),
- mValidated(false)
+ : mValue()
{}
ParamValue(value_assignment_t other)
- : mValue(other),
- mValidated(false)
+ : mValue(other)
{}
void setValue(value_assignment_t val)
@@ -2004,11 +2138,11 @@ namespace LLInitParam
return mValue.get().deserializeBlock(p, name_stack_range, new_name);
}
- void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
+ bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const
{
- if (mValue.empty()) return;
+ if (mValue.empty()) return false;
- mValue.get().serializeBlock(p, name_stack, diff_block);
+ return mValue.get().serializeBlock(p, name_stack, predicate_rule, diff_block);
}
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
@@ -2018,9 +2152,6 @@ namespace LLInitParam
return mValue.get().inspectBlock(p, name_stack, min_count, max_count);
}
- protected:
- mutable bool mValidated; // lazy validation flag
-
private:
BaseBlock::Lazy<T> mValue;
};
@@ -2037,12 +2168,10 @@ namespace LLInitParam
typedef const LLSD& value_assignment_t;
ParamValue()
- : mValidated(false)
{}
ParamValue(value_assignment_t other)
- : mValue(other),
- mValidated(false)
+ : mValue(other)
{}
void setValue(value_assignment_t val) { mValue = val; }
@@ -2056,16 +2185,13 @@ namespace LLInitParam
// block param interface
LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
- LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
+ LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const;
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
{
//TODO: implement LLSD params as schema type Any
return true;
}
- protected:
- mutable bool mValidated; // lazy validation flag
-
private:
static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack);
@@ -2094,8 +2220,7 @@ namespace LLInitParam
CustomParamValue(const T& value = T())
: mValue(value),
- mValueAge(VALUE_AUTHORITATIVE),
- mValidated(false)
+ mValueAge(VALUE_AUTHORITATIVE)
{}
bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name)
@@ -2119,7 +2244,7 @@ namespace LLInitParam
return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name);
}
- void serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
+ bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const
{
const derived_t& typed_param = static_cast<const derived_t&>(*this);
const derived_t* diff_param = static_cast<const derived_t*>(diff_block);
@@ -2131,14 +2256,18 @@ namespace LLInitParam
{
if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key))
{
- parser.writeValue(key, name_stack);
+ return parser.writeValue(key, name_stack);
}
}
// then try to serialize value directly
else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))
{
- if (!parser.writeValue(typed_param.getValue(), name_stack))
+ if (parser.writeValue(typed_param.getValue(), name_stack))
+ {
+ return true;
+ }
+ else
{
//RN: *always* serialize provided components of BlockValue (don't pass diff_param on),
// since these tend to be viewed as the constructor arguments for the value T. It seems
@@ -2155,14 +2284,15 @@ namespace LLInitParam
// and serialize those params
derived_t copy(typed_param);
copy.updateBlockFromValue(true);
- copy.block_t::serializeBlock(parser, name_stack, NULL);
+ return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
}
else
{
- block_t::serializeBlock(parser, name_stack, NULL);
+ return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
}
}
}
+ return false;
}
bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
@@ -2280,8 +2410,6 @@ namespace LLInitParam
return block_t::mergeBlock(block_data, source, overwrite);
}
- mutable bool mValidated; // lazy validation flag
-
private:
mutable T mValue;
mutable EValueAge mValueAge;
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
index 5dc3ea5d7b..071a637cda 100644
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -27,6 +27,8 @@
#include "linden_common.h"
// associated header
#include "llinstancetracker.h"
+#include "llapr.h"
+
// STL headers
// std headers
// external library headers
@@ -47,3 +49,19 @@ void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
InstancesMap::mapped_type()))
.first->second;
}
+
+void LLInstanceTrackerBase::StaticBase::incrementDepth()
+{
+ apr_atomic_inc32(&sIterationNestDepth);
+}
+
+void LLInstanceTrackerBase::StaticBase::decrementDepth()
+{
+ apr_atomic_dec32(&sIterationNestDepth);
+}
+
+U32 LLInstanceTrackerBase::StaticBase::getDepth()
+{
+ apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth);
+ return data;
+}
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 403df08990..9dd6d4a7ed 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -70,15 +70,20 @@ protected:
StaticBase():
sIterationNestDepth(0)
{}
- S32 sIterationNestDepth;
+
+ void incrementDepth();
+ void decrementDepth();
+ U32 getDepth();
+ private:
+ U32 sIterationNestDepth;
};
};
/// This mix-in class adds support for tracking all instances of the specified class parameter T
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
/// If KEY is not provided, then instances are stored in a simple set
-/// @NOTE: see explicit specialization below for default KEY==T* case
-template<typename T, typename KEY = T*>
+/// @NOTE: see explicit specialization below for default KEY==void case
+template<typename T, typename KEY = void>
class LLInstanceTracker : public LLInstanceTrackerBase
{
typedef LLInstanceTracker<T, KEY> MyT;
@@ -99,12 +104,12 @@ public:
instance_iter(const typename InstanceMap::iterator& it)
: mIterator(it)
{
- ++getStatic().sIterationNestDepth;
+ getStatic().incrementDepth();
}
~instance_iter()
{
- --getStatic().sIterationNestDepth;
+ getStatic().decrementDepth();
}
@@ -133,18 +138,18 @@ public:
key_iter(typename InstanceMap::iterator it)
: mIterator(it)
{
- ++getStatic().sIterationNestDepth;
+ getStatic().incrementDepth();
}
key_iter(const key_iter& other)
: mIterator(other.mIterator)
{
- ++getStatic().sIterationNestDepth;
+ getStatic().incrementDepth();
}
~key_iter()
{
- --getStatic().sIterationNestDepth;
+ getStatic().decrementDepth();
}
@@ -203,7 +208,7 @@ protected:
virtual ~LLInstanceTracker()
{
// it's unsafe to delete instances of this type while all instances are being iterated over.
- llassert_always(getStatic().sIterationNestDepth == 0);
+ llassert_always(getStatic().getDepth() == 0);
remove_();
}
virtual void setKey(KEY key) { remove_(); add_(key); }
@@ -224,12 +229,12 @@ private:
KEY mInstanceKey;
};
-/// explicit specialization for default case where KEY is T*
+/// explicit specialization for default case where KEY is void
/// use a simple std::set<T*>
template<typename T>
-class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
+class LLInstanceTracker<T, void> : public LLInstanceTrackerBase
{
- typedef LLInstanceTracker<T, T*> MyT;
+ typedef LLInstanceTracker<T, void> MyT;
typedef typename std::set<T*> InstanceSet;
struct StaticData: public StaticBase
{
@@ -262,18 +267,18 @@ public:
instance_iter(const typename InstanceSet::iterator& it)
: mIterator(it)
{
- ++getStatic().sIterationNestDepth;
+ getStatic().incrementDepth();
}
instance_iter(const instance_iter& other)
: mIterator(other.mIterator)
{
- ++getStatic().sIterationNestDepth;
+ getStatic().incrementDepth();
}
~instance_iter()
{
- --getStatic().sIterationNestDepth;
+ getStatic().decrementDepth();
}
private:
@@ -306,7 +311,7 @@ protected:
virtual ~LLInstanceTracker()
{
// it's unsafe to delete instances of this type while all instances are being iterated over.
- llassert_always(getStatic().sIterationNestDepth == 0);
+ llassert_always(getStatic().getDepth() == 0);
getSet_().erase(static_cast<T*>(this));
}
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index 0a57ef1c48..84d2a12f65 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -394,7 +394,7 @@ public:
LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN));
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
LLSD nop;
- F64 until(LLTimer::getElapsedSeconds() + 2);
+ F64 until = (LLTimer::getElapsedSeconds() + 2).value();
while (childin.size() && LLTimer::getElapsedSeconds() < until)
{
mainloop.post(nop);
diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp
index 1409c55d1c..ed80af36d8 100644
--- a/indra/llcommon/llmd5.cpp
+++ b/indra/llcommon/llmd5.cpp
@@ -76,7 +76,6 @@ documentation and/or software.
#include "llmd5.h"
-#include <cassert>
#include <iostream> // cerr
// how many bytes to grab at a time when checking files
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index 70ad10ad55..c6b02df939 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -32,7 +32,6 @@
//#endif
#if defined(LL_WINDOWS)
-//# include <windows.h>
# include <psapi.h>
#elif defined(LL_DARWIN)
# include <sys/types.h>
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 10013e0f92..4ead45679f 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -26,7 +26,12 @@
#ifndef LLMEMORY_H
#define LLMEMORY_H
-#include "llmemtype.h"
+#include "linden_common.h"
+#if !LL_WINDOWS
+#include <stdint.h>
+#endif
+
+class LLMutex ;
#if LL_WINDOWS && LL_DEBUG
#define LL_CHECK_MEMORY llassert(_CrtCheckMemory());
diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp
deleted file mode 100644
index 6290a7158f..0000000000
--- a/indra/llcommon/llmemtype.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/**
- * @file llmemtype.cpp
- * @brief Simple memory allocation/deallocation tracking stuff here
- *
- * $LicenseInfo:firstyear=2002&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$
- */
-
-#include "llmemtype.h"
-#include "llallocator.h"
-
-std::vector<char const *> LLMemType::DeclareMemType::mNameList;
-
-LLMemType::DeclareMemType LLMemType::MTYPE_INIT("Init");
-LLMemType::DeclareMemType LLMemType::MTYPE_STARTUP("Startup");
-LLMemType::DeclareMemType LLMemType::MTYPE_MAIN("Main");
-LLMemType::DeclareMemType LLMemType::MTYPE_FRAME("Frame");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_GATHER_INPUT("GatherInput");
-LLMemType::DeclareMemType LLMemType::MTYPE_JOY_KEY("JoyKey");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE("Idle");
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_PUMP("IdlePump");
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_NETWORK("IdleNetwork");
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_REGIONS("IdleUpdateRegions");
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION("IdleUpdateViewerRegion");
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_SURFACE("IdleUpdateSurface");
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_PARCEL_OVERLAY("IdleUpdateParcelOverlay");
-LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_AUDIO("IdleAudio");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING("CacheProcessPending");
-LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS("CacheProcessPendingAsks");
-LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES("CacheProcessPendingReplies");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_CHECK_ALL("MessageCheckAll");
-LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_PROCESS_ACKS("MessageProcessAcks");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_RENDER("Render");
-LLMemType::DeclareMemType LLMemType::MTYPE_SLEEP("Sleep");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_NETWORK("Network");
-LLMemType::DeclareMemType LLMemType::MTYPE_PHYSICS("Physics");
-LLMemType::DeclareMemType LLMemType::MTYPE_INTERESTLIST("InterestList");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEBASE("ImageBase");
-LLMemType::DeclareMemType LLMemType::MTYPE_IMAGERAW("ImageRaw");
-LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEFORMATTED("ImageFormatted");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_APPFMTIMAGE("AppFmtImage");
-LLMemType::DeclareMemType LLMemType::MTYPE_APPRAWIMAGE("AppRawImage");
-LLMemType::DeclareMemType LLMemType::MTYPE_APPAUXRAWIMAGE("AppAuxRawImage");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_DRAWABLE("Drawable");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT("Object");
-LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE("ObjectProcessUpdate");
-LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE_CORE("ObjectProcessUpdateCore");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY("Display");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE("DisplayUpdate");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA("DisplayUpdateCam");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_GEOM("DisplayUpdateGeom");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SWAP("DisplaySwap");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_HUD("DisplayUpdateHud");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_GEN_REFLECTION("DisplayGenRefl");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE("DisplayImageUpdate");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_STATE_SORT("DisplayStateSort");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SKY("DisplaySky");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_GEOM("DisplayRenderGeom");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_FLUSH("DisplayRenderFlush");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_UI("DisplayRenderUI");
-LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS("DisplayRenderAttach");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DATA("VertexData");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CONSTRUCTOR("VertexConstr");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTRUCTOR("VertexDestr");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_VERTICES("VertexCreateVerts");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_INDICES("VertexCreateIndices");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_BUFFER("VertexDestroyBuff");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_INDICES("VertexDestroyIndices");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_VERTS("VertexUpdateVerts");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_INDICES("VertexUpdateIndices");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER("VertexAllocateBuffer");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_RESIZE_BUFFER("VertexResizeBuffer");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER("VertexMapBuffer");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES("VertexMapBufferVerts");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES("VertexMapBufferIndices");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UNMAP_BUFFER("VertexUnmapBuffer");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_STRIDE("VertexSetStride");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_BUFFER("VertexSetBuffer");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER("VertexSetupVertBuff");
-LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CLEANUP_CLASS("VertexCleanupClass");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_SPACE_PARTITION("SpacePartition");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE("Pipeline");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_INIT("PipelineInit");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS("PipelineCreateBuffs");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RESTORE_GL("PipelineRestroGL");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS("PipelineUnloadShaders");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL("PipelineLightingDetail");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE("PipelineGetPoolType");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_POOL("PipelineAddPool");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE("PipelineAllocDrawable");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_OBJECT("PipelineAddObj");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS("PipelineCreateObjs");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_MOVE("PipelineUpdateMove");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_GEOM("PipelineUpdateGeom");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_VISIBLE("PipelineMarkVisible");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_MOVED("PipelineMarkMoved");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_SHIFT("PipelineMarkShift");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS("PipelineShiftObjs");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_TEXTURED("PipelineMarkTextured");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_REBUILD("PipelineMarkRebuild");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_CULL("PipelineUpdateCull");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_STATE_SORT("PipelineStateSort");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_POST_SORT("PipelinePostSort");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS("PipelineHudEls");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HL("PipelineRenderHL");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM("PipelineRenderGeom");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED("PipelineRenderGeomDef");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF("PipelineRenderGeomPostDef");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW("PipelineRenderGeomShadow");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_SELECT("PipelineRenderSelect");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_REBUILD_POOLS("PipelineRebuildPools");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP("PipelineQuickLookup");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS("PipelineRenderObjs");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR("PipelineGenImpostors");
-LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_BLOOM("PipelineRenderBloom");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_UPKEEP_POOLS("UpkeepPools");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR("Avatar");
-LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR_MESH("AvatarMesh");
-LLMemType::DeclareMemType LLMemType::MTYPE_PARTICLES("Particles");
-LLMemType::DeclareMemType LLMemType::MTYPE_REGIONS("Regions");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY("Inventory");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DRAW("InventoryDraw");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS("InventoryBuildNewViews");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DO_FOLDER("InventoryDoFolder");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_POST_BUILD("InventoryPostBuild");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_FROM_XML("InventoryFromXML");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_CREATE_NEW_ITEM("InventoryCreateNewItem");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_INIT("InventoryViewInit");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_SHOW("InventoryViewShow");
-LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE("InventoryViewToggle");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_ANIMATION("Animation");
-LLMemType::DeclareMemType LLMemType::MTYPE_VOLUME("Volume");
-LLMemType::DeclareMemType LLMemType::MTYPE_PRIMITIVE("Primitive");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT("Script");
-LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_RUN("ScriptRun");
-LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_BYTECODE("ScriptByteCode");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_IO_PUMP("IoPump");
-LLMemType::DeclareMemType LLMemType::MTYPE_IO_TCP("IoTCP");
-LLMemType::DeclareMemType LLMemType::MTYPE_IO_BUFFER("IoBuffer");
-LLMemType::DeclareMemType LLMemType::MTYPE_IO_HTTP_SERVER("IoHttpServer");
-LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_SERVER("IoSDServer");
-LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_CLIENT("IoSDClient");
-LLMemType::DeclareMemType LLMemType::MTYPE_IO_URL_REQUEST("IOUrlRequest");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_DIRECTX_INIT("DirectXInit");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP1("Temp1");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP2("Temp2");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP3("Temp3");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP4("Temp4");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP5("Temp5");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP6("Temp6");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP7("Temp7");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP8("Temp8");
-LLMemType::DeclareMemType LLMemType::MTYPE_TEMP9("Temp9");
-
-LLMemType::DeclareMemType LLMemType::MTYPE_OTHER("Other");
-
-
-LLMemType::DeclareMemType::DeclareMemType(char const * st)
-{
- mID = (S32)mNameList.size();
- mName = st;
-
- mNameList.push_back(mName);
-}
-
-LLMemType::DeclareMemType::~DeclareMemType()
-{
-}
-
-LLMemType::LLMemType(LLMemType::DeclareMemType& dt)
-{
- mTypeIndex = dt.mID;
- LLAllocator::pushMemType(dt.mID);
-}
-
-LLMemType::~LLMemType()
-{
- LLAllocator::popMemType();
-}
-
-char const * LLMemType::getNameFromID(S32 id)
-{
- if (id < 0 || id >= (S32)DeclareMemType::mNameList.size())
- {
- return "INVALID";
- }
-
- return DeclareMemType::mNameList[id];
-}
-
-//--------------------------------------------------------------------------------------------------
diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h
deleted file mode 100644
index 4945dbaf60..0000000000
--- a/indra/llcommon/llmemtype.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/**
- * @file llmemtype.h
- * @brief Runtime memory usage debugging utilities.
- *
- * $LicenseInfo:firstyear=2005&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_MEMTYPE_H
-#define LL_MEMTYPE_H
-
-//----------------------------------------------------------------------------
-//----------------------------------------------------------------------------
-
-//----------------------------------------------------------------------------
-
-#include "linden_common.h"
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// WARNING: Never commit with MEM_TRACK_MEM == 1
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-#define MEM_TRACK_MEM (0 && LL_WINDOWS)
-
-#include <vector>
-
-#define MEM_TYPE_NEW(T)
-
-class LL_COMMON_API LLMemType
-{
-public:
-
- // class we'll initialize all instances of as
- // static members of MemType. Then use
- // to construct any new mem type.
- class LL_COMMON_API DeclareMemType
- {
- public:
- DeclareMemType(char const * st);
- ~DeclareMemType();
-
- S32 mID;
- char const * mName;
-
- // array so we can map an index ID to Name
- static std::vector<char const *> mNameList;
- };
-
- LLMemType(DeclareMemType& dt);
- ~LLMemType();
-
- static char const * getNameFromID(S32 id);
-
- static DeclareMemType MTYPE_INIT;
- static DeclareMemType MTYPE_STARTUP;
- static DeclareMemType MTYPE_MAIN;
- static DeclareMemType MTYPE_FRAME;
-
- static DeclareMemType MTYPE_GATHER_INPUT;
- static DeclareMemType MTYPE_JOY_KEY;
-
- static DeclareMemType MTYPE_IDLE;
- static DeclareMemType MTYPE_IDLE_PUMP;
- static DeclareMemType MTYPE_IDLE_NETWORK;
- static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
- static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
- static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
- static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
- static DeclareMemType MTYPE_IDLE_AUDIO;
-
- static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
- static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
- static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
-
- static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
- static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
-
- static DeclareMemType MTYPE_RENDER;
- static DeclareMemType MTYPE_SLEEP;
-
- static DeclareMemType MTYPE_NETWORK;
- static DeclareMemType MTYPE_PHYSICS;
- static DeclareMemType MTYPE_INTERESTLIST;
-
- static DeclareMemType MTYPE_IMAGEBASE;
- static DeclareMemType MTYPE_IMAGERAW;
- static DeclareMemType MTYPE_IMAGEFORMATTED;
-
- static DeclareMemType MTYPE_APPFMTIMAGE;
- static DeclareMemType MTYPE_APPRAWIMAGE;
- static DeclareMemType MTYPE_APPAUXRAWIMAGE;
-
- static DeclareMemType MTYPE_DRAWABLE;
-
- static DeclareMemType MTYPE_OBJECT;
- static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
- static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
-
- static DeclareMemType MTYPE_DISPLAY;
- static DeclareMemType MTYPE_DISPLAY_UPDATE;
- static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
- static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
- static DeclareMemType MTYPE_DISPLAY_SWAP;
- static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
- static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
- static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
- static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
- static DeclareMemType MTYPE_DISPLAY_SKY;
- static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
- static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
- static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
- static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
-
- static DeclareMemType MTYPE_VERTEX_DATA;
- static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
- static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
- static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
- static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
- static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;
- static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
- static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
- static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
- static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
- static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
- static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
- static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
- static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
- static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
- static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
- static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
- static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
- static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
-
- static DeclareMemType MTYPE_SPACE_PARTITION;
-
- static DeclareMemType MTYPE_PIPELINE;
- static DeclareMemType MTYPE_PIPELINE_INIT;
- static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
- static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
- static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
- static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
- static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
- static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
- static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
- static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
- static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
- static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
- static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
- static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
- static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
- static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
- static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
- static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
- static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
- static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
- static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
- static DeclareMemType MTYPE_PIPELINE_POST_SORT;
-
- static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
- static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
- static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
- static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
- static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
- static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
- static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
- static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
- static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
-
- static DeclareMemType MTYPE_UPKEEP_POOLS;
-
- static DeclareMemType MTYPE_AVATAR;
- static DeclareMemType MTYPE_AVATAR_MESH;
- static DeclareMemType MTYPE_PARTICLES;
- static DeclareMemType MTYPE_REGIONS;
-
- static DeclareMemType MTYPE_INVENTORY;
- static DeclareMemType MTYPE_INVENTORY_DRAW;
- static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
- static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
- static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
- static DeclareMemType MTYPE_INVENTORY_FROM_XML;
- static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
- static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
- static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
- static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
-
- static DeclareMemType MTYPE_ANIMATION;
- static DeclareMemType MTYPE_VOLUME;
- static DeclareMemType MTYPE_PRIMITIVE;
-
- static DeclareMemType MTYPE_SCRIPT;
- static DeclareMemType MTYPE_SCRIPT_RUN;
- static DeclareMemType MTYPE_SCRIPT_BYTECODE;
-
- static DeclareMemType MTYPE_IO_PUMP;
- static DeclareMemType MTYPE_IO_TCP;
- static DeclareMemType MTYPE_IO_BUFFER;
- static DeclareMemType MTYPE_IO_HTTP_SERVER;
- static DeclareMemType MTYPE_IO_SD_SERVER;
- static DeclareMemType MTYPE_IO_SD_CLIENT;
- static DeclareMemType MTYPE_IO_URL_REQUEST;
-
- static DeclareMemType MTYPE_DIRECTX_INIT;
-
- static DeclareMemType MTYPE_TEMP1;
- static DeclareMemType MTYPE_TEMP2;
- static DeclareMemType MTYPE_TEMP3;
- static DeclareMemType MTYPE_TEMP4;
- static DeclareMemType MTYPE_TEMP5;
- static DeclareMemType MTYPE_TEMP6;
- static DeclareMemType MTYPE_TEMP7;
- static DeclareMemType MTYPE_TEMP8;
- static DeclareMemType MTYPE_TEMP9;
-
- static DeclareMemType MTYPE_OTHER; // Special; used by display code
-
- S32 mTypeIndex;
-};
-
-//----------------------------------------------------------------------------
-
-#endif
-
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index 41d3eb0bf3..aaacbfb599 100644
--- a/indra/llcommon/llmetricperformancetester.cpp
+++ b/indra/llcommon/llmetricperformancetester.cpp
@@ -29,9 +29,9 @@
#include "indra_constants.h"
#include "llerror.h"
#include "llsdserialize.h"
-#include "llstat.h"
#include "lltreeiterators.h"
#include "llmetricperformancetester.h"
+#include "llfasttimer.h"
//----------------------------------------------------------------------------------------------
// LLMetricPerformanceTesterBasic : static methods and testers management
@@ -91,7 +91,7 @@ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::s
// Return TRUE if this metric is requested or if the general default "catch all" metric is requested
BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name)
{
- return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME)));
+ return (LLTrace::TimeBlock::sMetricLog && ((LLTrace::TimeBlock::sLogName == name) || (LLTrace::TimeBlock::sLogName == DEFAULT_METRIC_NAME)));
}
/*static*/
@@ -194,8 +194,7 @@ void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
{
- LLMutexLock lock(LLFastTimer::sLogLock);
- LLFastTimer::sLogQueue.push((*sd));
+ LLTrace::TimeBlock::pushLog(*sd);
}
void LLMetricPerformanceTesterBasic::outputTestResults()
diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h
index 319955ef93..9517e2db5e 100644
--- a/indra/llcommon/llmortician.h
+++ b/indra/llcommon/llmortician.h
@@ -28,6 +28,7 @@
#define LLMORTICIAN_H
#include "stdtypes.h"
+#include <list>
class LL_COMMON_API LLMortician
{
diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp
new file mode 100644
index 0000000000..b685bb4d60
--- /dev/null
+++ b/indra/llcommon/llmutex.cpp
@@ -0,0 +1,176 @@
+/**
+ * @file llmutex.cpp
+ *
+ * $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$
+ */
+
+#include "linden_common.h"
+#include "llapr.h"
+
+#include "apr_portable.h"
+
+#include "llmutex.h"
+#include "llthread.h"
+
+//============================================================================
+
+LLMutex::LLMutex(apr_pool_t *poolp) :
+ mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
+{
+ //if (poolp)
+ //{
+ // mIsLocalPool = FALSE;
+ // mAPRPoolp = poolp;
+ //}
+ //else
+ {
+ mIsLocalPool = TRUE;
+ apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
+ }
+ apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
+}
+
+
+LLMutex::~LLMutex()
+{
+#if MUTEX_DEBUG
+ //bad assertion, the subclass LLSignal might be "locked", and that's OK
+ //llassert_always(!isLocked()); // better not be locked!
+#endif
+ apr_thread_mutex_destroy(mAPRMutexp);
+ mAPRMutexp = NULL;
+ if (mIsLocalPool)
+ {
+ apr_pool_destroy(mAPRPoolp);
+ }
+}
+
+
+void LLMutex::lock()
+{
+ if(isSelfLocked())
+ { //redundant lock
+ mCount++;
+ return;
+ }
+
+ apr_thread_mutex_lock(mAPRMutexp);
+
+#if MUTEX_DEBUG
+ // Have to have the lock before we can access the debug info
+ U32 id = LLThread::currentID();
+ if (mIsLocked[id] != FALSE)
+ llerrs << "Already locked in Thread: " << id << llendl;
+ mIsLocked[id] = TRUE;
+#endif
+
+ mLockingThread = LLThread::currentID();
+}
+
+void LLMutex::unlock()
+{
+ if (mCount > 0)
+ { //not the root unlock
+ mCount--;
+ return;
+ }
+
+#if MUTEX_DEBUG
+ // Access the debug info while we have the lock
+ U32 id = LLThread::currentID();
+ if (mIsLocked[id] != TRUE)
+ llerrs << "Not locked in Thread: " << id << llendl;
+ mIsLocked[id] = FALSE;
+#endif
+
+ mLockingThread = NO_THREAD;
+ apr_thread_mutex_unlock(mAPRMutexp);
+}
+
+bool LLMutex::isLocked()
+{
+ apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
+ if (APR_STATUS_IS_EBUSY(status))
+ {
+ return true;
+ }
+ else
+ {
+ apr_thread_mutex_unlock(mAPRMutexp);
+ return false;
+ }
+}
+
+bool LLMutex::isSelfLocked()
+{
+ return mLockingThread == LLThread::currentID();
+}
+
+U32 LLMutex::lockingThread() const
+{
+ return mLockingThread;
+}
+
+//============================================================================
+
+LLCondition::LLCondition(apr_pool_t *poolp) :
+ LLMutex(poolp)
+{
+ // base class (LLMutex) has already ensured that mAPRPoolp is set up.
+
+ apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
+}
+
+
+LLCondition::~LLCondition()
+{
+ apr_thread_cond_destroy(mAPRCondp);
+ mAPRCondp = NULL;
+}
+
+
+void LLCondition::wait()
+{
+ if (!isLocked())
+ { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
+ apr_thread_mutex_lock(mAPRMutexp);
+#if MUTEX_DEBUG
+ // avoid asserts on destruction in non-release builds
+ U32 id = LLThread::currentID();
+ mIsLocked[id] = TRUE;
+#endif
+ }
+ apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
+}
+
+void LLCondition::signal()
+{
+ apr_thread_cond_signal(mAPRCondp);
+}
+
+void LLCondition::broadcast()
+{
+ apr_thread_cond_broadcast(mAPRCondp);
+}
+
+
+//============================================================================
diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h
new file mode 100644
index 0000000000..cbde4c47a9
--- /dev/null
+++ b/indra/llcommon/llmutex.h
@@ -0,0 +1,101 @@
+/**
+ * @file llmutex.h
+ * @brief Base classes for mutex and condition handling.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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_LLMUTEX_H
+#define LL_LLMUTEX_H
+
+#include "llapr.h"
+#include "apr_thread_cond.h"
+
+//============================================================================
+
+#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
+
+class LL_COMMON_API LLMutex
+{
+public:
+ typedef enum
+ {
+ NO_THREAD = 0xFFFFFFFF
+ } e_locking_thread;
+
+ LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex
+ virtual ~LLMutex();
+
+ void lock(); // blocks
+ void unlock();
+ bool isLocked(); // non-blocking, but does do a lock/unlock so not free
+ bool isSelfLocked(); //return true if locked in a same thread
+ U32 lockingThread() const; //get ID of locking thread
+
+protected:
+ apr_thread_mutex_t *mAPRMutexp;
+ mutable U32 mCount;
+ mutable U32 mLockingThread;
+
+ apr_pool_t *mAPRPoolp;
+ BOOL mIsLocalPool;
+
+#if MUTEX_DEBUG
+ std::map<U32, BOOL> mIsLocked;
+#endif
+};
+
+// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
+class LL_COMMON_API LLCondition : public LLMutex
+{
+public:
+ LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
+ ~LLCondition();
+
+ void wait(); // blocks
+ void signal();
+ void broadcast();
+
+protected:
+ apr_thread_cond_t *mAPRCondp;
+};
+
+class LLMutexLock
+{
+public:
+ LLMutexLock(LLMutex* mutex)
+ {
+ mMutex = mutex;
+
+ if(mMutex)
+ mMutex->lock();
+ }
+ ~LLMutexLock()
+ {
+ if(mMutex)
+ mMutex->unlock();
+ }
+private:
+ LLMutex* mMutex;
+};
+
+#endif // LL_LLTHREAD_H
diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h
index 88c09c8dca..f03551045e 100644
--- a/indra/llcommon/llpointer.h
+++ b/indra/llcommon/llpointer.h
@@ -97,24 +97,13 @@ public:
LLPointer<Type>& operator =(Type* ptr)
{
- if( mPointer != ptr )
- {
- unref();
- mPointer = ptr;
- ref();
- }
-
+ assign(ptr);
return *this;
}
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
{
- if( mPointer != ptr.mPointer )
- {
- unref();
- mPointer = ptr.mPointer;
- ref();
- }
+ assign(ptr);
return *this;
}
@@ -122,12 +111,7 @@ public:
template<typename Subclass>
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
{
- if( mPointer != ptr.get() )
- {
- unref();
- mPointer = ptr.get();
- ref();
- }
+ assign(ptr.get());
return *this;
}
@@ -144,6 +128,16 @@ protected:
void ref();
void unref();
#else
+
+ void assign(const LLPointer<Type>& ptr)
+ {
+ if( mPointer != ptr.mPointer )
+ {
+ unref();
+ mPointer = ptr.mPointer;
+ ref();
+ }
+ }
void ref()
{
if (mPointer)
@@ -156,9 +150,9 @@ protected:
{
if (mPointer)
{
- Type *tempp = mPointer;
+ Type *temp = mPointer;
mPointer = NULL;
- tempp->unref();
+ temp->unref();
if (mPointer != NULL)
{
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
@@ -171,4 +165,53 @@ protected:
Type* mPointer;
};
+template<typename Type>
+class LLCopyOnWritePointer
+{
+public:
+ typedef LLCopyOnWritePointer<Type> self_t;
+
+ LLCopyOnWritePointer()
+ {}
+
+ LLCopyOnWritePointer(Type* ptr)
+ : mPointer(ptr)
+ {}
+
+ LLCopyOnWritePointer(LLPointer<Type>& ptr)
+ : mPointer(ptr)
+ {}
+
+ Type* write()
+ {
+ makeUnique();
+ return mPointer.get();
+ }
+
+ void makeUnique()
+ {
+ if (mPointer.notNull() && mPointer.get()->getNumRefs() > 1)
+ {
+ mPointer = new Type(*mPointer.get());
+ }
+ }
+
+ operator BOOL() const { return (BOOL)mPointer; }
+ operator bool() const { return (bool)mPointer; }
+ bool operator!() const { return !mPointer; }
+ bool isNull() const { return mPointer.isNull(); }
+ bool notNull() const { return mPointer.notNull(); }
+
+ bool operator !=(Type* ptr) const { return (mPointer.get() != ptr); }
+ bool operator ==(Type* ptr) const { return (mPointer.get() == ptr); }
+ bool operator ==(const LLCopyOnWritePointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
+ bool operator < (const LLCopyOnWritePointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
+ bool operator > (const LLCopyOnWritePointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
+
+ operator const Type*() const { return mPointer.get(); }
+ const Type* operator->() const { return mPointer.get(); }
+protected:
+ LLPointer<Type> mPointer;
+};
+
#endif
diff --git a/indra/llcommon/llpredicate.cpp b/indra/llcommon/llpredicate.cpp
new file mode 100644
index 0000000000..1278948e24
--- /dev/null
+++ b/indra/llcommon/llpredicate.cpp
@@ -0,0 +1,41 @@
+/**
+ * @file llpredicate.cpp
+ * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions
+ *
+ * $LicenseInfo:firstyear=2008&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$
+ */
+#include "linden_common.h"
+
+#include "llpredicate.h"
+
+namespace LLPredicate
+{
+ const U32 cPredicateFlagsFromEnum[5] =
+ {
+ 0xAAAAaaaa, // 10101010101010101010101010101010
+ 0xCCCCcccc, // 11001100110011001100110011001100
+ 0xF0F0F0F0, // 11110000111100001111000011110000
+ 0xFF00FF00, // 11111111000000001111111100000000
+ 0xFFFF0000 // 11111111111111110000000000000000
+ };
+}
+
diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h
new file mode 100644
index 0000000000..a0e970a799
--- /dev/null
+++ b/indra/llcommon/llpredicate.h
@@ -0,0 +1,210 @@
+/**
+ * @file llpredicate.h
+ * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions
+ *
+ * $LicenseInfo:firstyear=2008&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_LLPREDICATE_H
+#define LL_LLPREDICATE_H
+
+#include "llerror.h"
+
+namespace LLPredicate
+{
+ template<typename ENUM> class Rule;
+
+ extern const U32 cPredicateFlagsFromEnum[5];
+
+ template<typename ENUM>
+ class Value
+ {
+ public:
+ typedef U32 predicate_flag_t;
+ static const S32 cMaxEnum = 5;
+
+ Value(ENUM e, bool predicate_value = true)
+ : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e])
+ {
+ llassert(0 <= e && e < cMaxEnum);
+ }
+
+ Value()
+ : mPredicateFlags(0xFFFFffff)
+ {}
+
+ Value operator!() const
+ {
+ Value new_value;
+ new_value.mPredicateFlags = ~mPredicateFlags;
+ return new_value;
+ }
+
+ Value operator &&(const Value other) const
+ {
+ Value new_value;
+ new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags;
+ return new_value;
+ }
+
+ Value operator ||(const Value other) const
+ {
+ Value new_value;
+ new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags;
+ return new_value;
+ }
+
+ void set(ENUM e, bool value = true)
+ {
+ llassert(0 <= e && e < cMaxEnum);
+ predicate_flag_t flags_to_modify;
+ predicate_flag_t mask = cPredicateFlagsFromEnum[e];
+ if (value)
+ { // add predicate "e" to flags that don't contain it already
+ flags_to_modify = (mPredicateFlags & ~mask);
+ // clear flags not containing e
+ mPredicateFlags &= mask;
+ // add back flags shifted to contain e
+ mPredicateFlags |= flags_to_modify << (0x1 << e);
+ }
+ else
+ { // remove predicate "e" from flags that contain it
+ flags_to_modify = (mPredicateFlags & mask);
+ // clear flags containing e
+ mPredicateFlags &= ~mask;
+ // add back flags shifted to not contain e
+ mPredicateFlags |= flags_to_modify >> (0x1 << e);
+ }
+ }
+
+ void forget(ENUM e)
+ {
+ set(e, true);
+ U32 flags_with_predicate = mPredicateFlags;
+ set(e, false);
+ // ambiguous value is result of adding and removing predicate at the same time!
+ mPredicateFlags |= flags_with_predicate;
+ }
+
+ bool allSet() const
+ {
+ return mPredicateFlags == ~0;
+ }
+
+ bool noneSet() const
+ {
+ return mPredicateFlags == 0;
+ }
+
+ bool someSet() const
+ {
+ return mPredicateFlags != 0;
+ }
+
+ private:
+ predicate_flag_t mPredicateFlags;
+ };
+
+ template<typename ENUM>
+ class Rule
+ {
+ public:
+ Rule(ENUM value)
+ : mRule(value)
+ {}
+
+ Rule(const Value<ENUM> other)
+ : mRule(other)
+ {}
+
+ Rule()
+ {}
+
+ void require(ENUM e)
+ {
+ mRule.set(e, require);
+ }
+
+ void allow(ENUM e)
+ {
+ mRule.forget(e);
+ }
+
+ bool check(const Value<ENUM> value) const
+ {
+ return (mRule && value).someSet();
+ }
+
+ bool requires(const Value<ENUM> value) const
+ {
+ return (mRule && value).someSet() && (!mRule && value).noneSet();
+ }
+
+ bool isAmbivalent(const Value<ENUM> value) const
+ {
+ return (mRule && value).someSet() && (!mRule && value).someSet();
+ }
+
+ bool acceptsAll() const
+ {
+ return mRule.allSet();
+ }
+
+ bool acceptsNone() const
+ {
+ return mRule.noneSet();
+ }
+
+ Rule operator!() const
+ {
+ Rule new_rule;
+ new_rule.mRule = !mRule;
+ return new_rule;
+ }
+
+ Rule operator &&(const Rule other) const
+ {
+ Rule new_rule;
+ new_rule.mRule = mRule && other.mRule;
+ return new_rule;
+ }
+
+ Rule operator ||(const Rule other) const
+ {
+ Rule new_rule;
+ new_rule.mRule = mRule || other.mRule;
+ return new_rule;
+ }
+
+ private:
+ Value<ENUM> mRule;
+ };
+}
+
+template<typename ENUM>
+LLPredicate::Value<ENUM> ll_make_predicate(ENUM e, bool predicate_value = true)
+{
+ return LLPredicate::Value<ENUM>(e, predicate_value);
+}
+
+
+#endif // LL_LLPREDICATE_H
diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h
index d711ce2f74..2fe084afcd 100644
--- a/indra/llcommon/llprocess.h
+++ b/indra/llcommon/llprocess.h
@@ -38,8 +38,7 @@
#include <stdexcept>
#if LL_WINDOWS
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h> // HANDLE (eye roll)
+#include "llwin32headerslean.h" // for HANDLE
#elif LL_LINUX
#if defined(Status)
#undef Status
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index fd8f603d21..5ddfa6fcef 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -32,9 +32,7 @@
//#include <memory>
#if LL_WINDOWS
-# define WIN32_LEAN_AND_MEAN
-# include <winsock2.h>
-# include <windows.h>
+# include "llwin32headerslean.h"
# define _interlockedbittestandset _renamed_interlockedbittestandset
# define _interlockedbittestandreset _renamed_interlockedbittestandreset
# include <intrin.h>
@@ -877,7 +875,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL)
LLProcessorInfo::~LLProcessorInfo() {}
-F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
+LLUnitImplicit<LLUnits::Megahertz, F64> LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h
index 6364d3c8bb..fbd427f484 100644
--- a/indra/llcommon/llprocessor.h
+++ b/indra/llcommon/llprocessor.h
@@ -27,6 +27,8 @@
#ifndef LLPROCESSOR_H
#define LLPROCESSOR_H
+#include "llunit.h"
+
class LLProcessorInfoImpl;
class LL_COMMON_API LLProcessorInfo
@@ -35,7 +37,7 @@ public:
LLProcessorInfo();
~LLProcessorInfo();
- F64 getCPUFrequency() const;
+ LLUnitImplicit<LLUnits::Megahertz, F64> getCPUFrequency() const;
bool hasSSE() const;
bool hasSSE2() const;
bool hasAltivec() const;
diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index abf47a0f57..956642e97a 100644
--- a/indra/llcommon/llqueuedthread.cpp
+++ b/indra/llcommon/llqueuedthread.cpp
@@ -28,6 +28,7 @@
#include "llstl.h"
#include "lltimer.h" // ms_sleep()
+#include "lltracethreadrecorder.h"
//============================================================================
@@ -134,8 +135,8 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms)
pending = getPending();
if(pending > 0)
{
- unpause();
- }
+ unpause();
+ }
}
else
{
@@ -508,6 +509,9 @@ void LLQueuedThread::run()
threadedUpdate();
int res = processNextRequest();
+
+ LLTrace::get_thread_recorder()->pushToMaster();
+
if (res == 0)
{
mIdleThread = TRUE;
diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp
index 0e29873bb0..345e30f4b4 100644
--- a/indra/llcommon/llsdparam.cpp
+++ b/indra/llcommon/llsdparam.cpp
@@ -102,13 +102,13 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool
//readSDValues(sd, block);
}
-void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)
+void LLParamSDParser::writeSDImpl(LLSD& sd, const LLInitParam::BaseBlock& block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block)
{
mNameStack.clear();
mWriteRootSD = &sd;
name_stack_t name_stack;
- block.serializeBlock(*this, name_stack);
+ block.serializeBlock(*this, name_stack, rules, diff_block);
}
/*virtual*/ std::string LLParamSDParser::getCurrentElementName()
@@ -223,10 +223,14 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
{
bool new_traversal = it->second;
- LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first];
-
- if (child_sd->isArray())
+ LLSD* child_sd;
+ if (it->first.empty())
+ {
+ child_sd = sd_to_write;
+ if (child_sd->isUndefined())
{
+ *child_sd = LLSD::emptyArray();
+ }
if (new_traversal)
{
// write to new element at end
@@ -240,22 +244,7 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
}
else
{
- if (new_traversal
- && child_sd->isDefined()
- && !child_sd->isArray())
- {
- // copy child contents into first element of an array
- LLSD new_array = LLSD::emptyArray();
- new_array.append(*child_sd);
- // assign array to slot that previously held the single value
- *child_sd = new_array;
- // return next element in that array
- sd_to_write = &((*child_sd)[1]);
- }
- else
- {
- sd_to_write = child_sd;
- }
+ sd_to_write = &(*sd_to_write)[it->first];
}
it->second = false;
}
@@ -283,8 +272,9 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI
it != sd.endArray();
++it)
{
- stack.back().second = true;
+ stack.push_back(make_pair(std::string(), true));
readSDValues(cb, *it, stack);
+ stack.pop_back();
}
}
else if (sd.isUndefined())
@@ -315,6 +305,12 @@ namespace LLInitParam
// block param interface
bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name)
{
+ if (name_stack.first == name_stack.second
+ && p.readValue<LLSD>(mValue))
+ {
+ return true;
+ }
+
LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack);
LLSD::String string;
@@ -333,10 +329,14 @@ namespace LLInitParam
p.writeValue<LLSD::String>(sd.asString(), name_stack);
}
- void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
+ bool ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const
{
- // read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
- Parser::name_stack_t stack;
- LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack);
+ // attempt to write LLSD out directly
+ if (!p.writeValue<LLSD>(mValue, name_stack))
+ {
+ // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
+ LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack);
+ }
+ return true;
}
}
diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h
index 6ef5debd7b..7cfc265c62 100644
--- a/indra/llcommon/llsdparam.h
+++ b/indra/llcommon/llsdparam.h
@@ -30,6 +30,7 @@
#include "llinitparam.h"
#include "boost/function.hpp"
+#include "llfasttimer.h"
struct LL_COMMON_API LLParamSDParserUtilities
{
@@ -50,11 +51,28 @@ typedef LLInitParam::Parser parser_t;
public:
LLParamSDParser();
void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false);
- void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block);
+ template<typename BLOCK>
+ void writeSD(LLSD& sd,
+ const BLOCK& block,
+ const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(),
+ const LLInitParam::BaseBlock* diff_block = NULL)
+ {
+ if (!diff_block
+ && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE))
+ {
+ diff_block = &LLInitParam::defaultValue<BLOCK>();
+ }
+ writeSDImpl(sd, block, rules, diff_block);
+ }
/*virtual*/ std::string getCurrentElementName();
private:
+ void writeSDImpl(LLSD& sd,
+ const LLInitParam::BaseBlock& block,
+ const LLInitParam::predicate_rule_t,
+ const LLInitParam::BaseBlock* diff_block);
+
void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack);
template<typename T>
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/llskipmap.h b/indra/llcommon/llskipmap.h
index 49ff2928d1..ed53973baa 100644
--- a/indra/llcommon/llskipmap.h
+++ b/indra/llcommon/llskipmap.h
@@ -210,8 +210,7 @@ inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap()
: mInsertFirst(NULL),
mEquals(defaultEquals)
{
- // Skipmaps must have binary depth of at least 2
- cassert(BINARY_DEPTH >= 2);
+ llstatic_assert(BINARY_DEPTH >= 2, "Skipmaps must have binary depth of at least 2");
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
@@ -229,8 +228,7 @@ inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap(BOOL (*insert_f
: mInsertFirst(insert_first),
mEquals(equals)
{
- // Skipmaps must have binary depth of at least 2
- cassert(BINARY_DEPTH >= 2);
+ llstatic_assert(BINARY_DEPTH >= 2, "Skipmaps must have binary depth of at least 2");
mLevel = 1;
S32 i;
diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp
index ccd7ef91c2..e0e9056380 100644
--- a/indra/llcommon/llstacktrace.cpp
+++ b/indra/llcommon/llstacktrace.cpp
@@ -32,7 +32,7 @@
#include <iostream>
#include <sstream>
-#include "windows.h"
+#include "llwin32headerslean.h"
#include "Dbghelp.h"
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp
deleted file mode 100644
index b82d52797e..0000000000
--- a/indra/llcommon/llstat.cpp
+++ /dev/null
@@ -1,1311 +0,0 @@
-/**
- * @file llstat.cpp
- *
- * $LicenseInfo:firstyear=2001&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$
- */
-
-#include "linden_common.h"
-
-#include "llstat.h"
-#include "lllivefile.h"
-#include "llerrorcontrol.h"
-#include "llframetimer.h"
-#include "timing.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-#include "llstl.h"
-#include "u64.h"
-
-
-// statics
-S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
-LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
-std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
-
-//------------------------------------------------------------------------
-// Live config file to trigger stats logging
-static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd";
-static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds
-
-class LLStatsConfigFile : public LLLiveFile
-{
-public:
- LLStatsConfigFile()
- : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE),
- mChanged(false), mStatsp(NULL) { }
-
- static std::string filename();
-
-protected:
- /* virtual */ bool loadFile();
-
-public:
- void init(LLPerfStats* statsp);
- static LLStatsConfigFile& instance();
- // return the singleton stats config file
-
- bool mChanged;
-
-protected:
- LLPerfStats* mStatsp;
-};
-
-std::string LLStatsConfigFile::filename()
-{
- return STATS_CONFIG_FILE_NAME;
-}
-
-void LLStatsConfigFile::init(LLPerfStats* statsp)
-{
- mStatsp = statsp;
-}
-
-LLStatsConfigFile& LLStatsConfigFile::instance()
-{
- static LLStatsConfigFile the_file;
- return the_file;
-}
-
-
-/* virtual */
-// Load and parse the stats configuration file
-bool LLStatsConfigFile::loadFile()
-{
- if (!mStatsp)
- {
- llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl;
- return false;
- }
- mChanged = true;
-
- LLSD stats_config;
- {
- llifstream file(filename().c_str());
- if (file.is_open())
- {
- LLSDSerialize::fromXML(stats_config, file);
- if (stats_config.isUndefined())
- {
- llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl;
- mStatsp->setReportPerformanceDuration( 0.f );
- return false;
- }
- }
- else
- { // File went away, turn off stats if it was on
- if ( mStatsp->frameStatsIsRunning() )
- {
- llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl;
- mStatsp->setReportPerformanceDuration( 0.f );
- }
- return true;
- }
- }
-
- F32 duration = 0.f;
- F32 interval = 0.f;
- S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
-
- const char * w = "duration";
- if (stats_config.has(w))
- {
- duration = (F32)stats_config[w].asReal();
- }
- w = "interval";
- if (stats_config.has(w))
- {
- interval = (F32)stats_config[w].asReal();
- }
- w = "flags";
- if (stats_config.has(w))
- {
- flags = (S32)stats_config[w].asInteger();
- if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
- duration > 0)
- { // No flags passed in, but have a duration, so reset to basic stats
- flags = LLPerfBlock::LLSTATS_BASIC_STATS;
- }
- }
-
- mStatsp->setReportPerformanceDuration( duration, flags );
- mStatsp->setReportPerformanceInterval( interval );
-
- if ( duration > 0 )
- {
- if ( interval == 0.f )
- {
- llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl;
- }
- else
- {
- llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl;
- }
- }
- else
- {
- llinfos << "Performance stats recording turned off" << llendl;
- }
- return true;
-}
-
-
-//------------------------------------------------------------------------
-
-LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) :
- mFrameStatsFileFailure(FALSE),
- mSkipFirstFrameStats(FALSE),
- mProcessName(process_name),
- mProcessPID(process_pid),
- mReportPerformanceStatInterval(1.f),
- mReportPerformanceStatEnd(0.0)
-{ }
-
-LLPerfStats::~LLPerfStats()
-{
- LLPerfBlock::clearDynamicStats();
- mFrameStatsFile.close();
-}
-
-void LLPerfStats::init()
-{
- // Initialize the stats config file instance.
- (void) LLStatsConfigFile::instance().init(this);
- (void) LLStatsConfigFile::instance().checkAndReload();
-}
-
-// Open file for statistics
-void LLPerfStats::openPerfStatsFile()
-{
- if ( !mFrameStatsFile
- && !mFrameStatsFileFailure )
- {
- std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID);
- mFrameStatsFile.close();
- mFrameStatsFile.clear();
- mFrameStatsFile.open(stats_file, llofstream::out);
- if ( mFrameStatsFile.fail() )
- {
- llinfos << "Error opening statistics log file " << stats_file << llendl;
- mFrameStatsFileFailure = TRUE;
- }
- else
- {
- LLSD process_info = LLSD::emptyMap();
- process_info["name"] = mProcessName;
- process_info["pid"] = (LLSD::Integer) mProcessPID;
- process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval;
- // Add process-specific info.
- addProcessHeaderInfo(process_info);
-
- mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl;
- }
- }
-}
-
-// Dump out performance metrics over some time interval
-void LLPerfStats::dumpIntervalPerformanceStats()
-{
- // Ensure output file is OK
- openPerfStatsFile();
-
- if ( mFrameStatsFile )
- {
- LLSD stats = LLSD::emptyMap();
-
- LLStatAccum::TimeScale scale;
- if ( getReportPerformanceInterval() == 0.f )
- {
- scale = LLStatAccum::SCALE_PER_FRAME;
- }
- else if ( getReportPerformanceInterval() < 0.5f )
- {
- scale = LLStatAccum::SCALE_100MS;
- }
- else
- {
- scale = LLStatAccum::SCALE_SECOND;
- }
-
- // Write LLSD into log
- stats["utc_time"] = (LLSD::String) LLError::utcTime();
- stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch
- stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount();
-
- // Add process-specific frame info.
- addProcessFrameInfo(stats, scale);
- LLPerfBlock::addStatsToLLSDandReset( stats, scale );
-
- mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl;
- }
-}
-
-// Set length of performance stat recording.
-// If turning stats on, caller must provide flags
-void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
-{
- if ( seconds <= 0.f )
- {
- mReportPerformanceStatEnd = 0.0;
- LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
- mFrameStatsFile.close();
- LLPerfBlock::clearDynamicStats();
- }
- else
- {
- mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
- // Clear failure flag to try and create the log file once
- mFrameStatsFileFailure = FALSE;
- mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
- LLPerfBlock::setStatsFlags(flags);
- }
-}
-
-void LLPerfStats::updatePerFrameStats()
-{
- (void) LLStatsConfigFile::instance().checkAndReload();
- static LLFrameTimer performance_stats_timer;
- if ( frameStatsIsRunning() )
- {
- if ( mReportPerformanceStatInterval == 0 )
- { // Record info every frame
- if ( mSkipFirstFrameStats )
- { // Skip the first time - was started this frame
- mSkipFirstFrameStats = FALSE;
- }
- else
- {
- dumpIntervalPerformanceStats();
- }
- }
- else
- {
- performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() );
- if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval ))
- {
- dumpIntervalPerformanceStats();
- }
- }
-
- if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd )
- { // Reached end of time, clear it to stop reporting
- setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly
- llinfos << "Recording performance stats completed" << llendl;
- }
- }
-}
-
-
-//------------------------------------------------------------------------
-
-U64 LLStatAccum::sScaleTimes[NUM_SCALES] =
-{
- USEC_PER_SEC / 10, // 100 millisec
- USEC_PER_SEC * 1, // seconds
- USEC_PER_SEC * 60, // minutes
-#if ENABLE_LONG_TIME_STATS
- // enable these when more time scales are desired
- USEC_PER_SEC * 60*60, // hours
- USEC_PER_SEC * 24*60*60, // days
- USEC_PER_SEC * 7*24*60*60, // weeks
-#endif
-};
-
-
-
-LLStatAccum::LLStatAccum(bool useFrameTimer)
- : mUseFrameTimer(useFrameTimer),
- mRunning(FALSE),
- mLastTime(0),
- mLastSampleValue(0.0),
- mLastSampleValid(FALSE)
-{
-}
-
-LLStatAccum::~LLStatAccum()
-{
-}
-
-
-
-void LLStatAccum::reset(U64 when)
-{
- mRunning = TRUE;
- mLastTime = when;
-
- for (int i = 0; i < NUM_SCALES; ++i)
- {
- mBuckets[i].accum = 0.0;
- mBuckets[i].endTime = when + sScaleTimes[i];
- mBuckets[i].lastValid = false;
- }
-}
-
-void LLStatAccum::sum(F64 value)
-{
- sum(value, getCurrentUsecs());
-}
-
-void LLStatAccum::sum(F64 value, U64 when)
-{
- if (!mRunning)
- {
- reset(when);
- return;
- }
- if (when < mLastTime)
- {
- // This happens a LOT on some dual core systems.
- lldebugs << "LLStatAccum::sum clock has gone backwards from "
- << mLastTime << " to " << when << ", resetting" << llendl;
-
- reset(when);
- return;
- }
-
- // how long is this value for
- U64 timeSpan = when - mLastTime;
-
- for (int i = 0; i < NUM_SCALES; ++i)
- {
- Bucket& bucket = mBuckets[i];
-
- if (when < bucket.endTime)
- {
- bucket.accum += value;
- }
- else
- {
- U64 timeScale = sScaleTimes[i];
-
- U64 timeLeft = when - bucket.endTime;
- // how much time is left after filling this bucket
-
- if (timeLeft < timeScale)
- {
- F64 valueLeft = value * timeLeft / timeSpan;
-
- bucket.lastValid = true;
- bucket.lastAccum = bucket.accum + (value - valueLeft);
- bucket.accum = valueLeft;
- bucket.endTime += timeScale;
- }
- else
- {
- U64 timeTail = timeLeft % timeScale;
-
- bucket.lastValid = true;
- bucket.lastAccum = value * timeScale / timeSpan;
- bucket.accum = value * timeTail / timeSpan;
- bucket.endTime += (timeLeft - timeTail) + timeScale;
- }
- }
- }
-
- mLastTime = when;
-}
-
-
-F32 LLStatAccum::meanValue(TimeScale scale) const
-{
- if (!mRunning)
- {
- return 0.0;
- }
- if ( scale == SCALE_PER_FRAME )
- { // Per-frame not supported here
- scale = SCALE_100MS;
- }
-
- if (scale < 0 || scale >= NUM_SCALES)
- {
- llwarns << "llStatAccum::meanValue called for unsupported scale: "
- << scale << llendl;
- return 0.0;
- }
-
- const Bucket& bucket = mBuckets[scale];
-
- F64 value = bucket.accum;
- U64 timeLeft = bucket.endTime - mLastTime;
- U64 scaleTime = sScaleTimes[scale];
-
- if (bucket.lastValid)
- {
- value += bucket.lastAccum * timeLeft / scaleTime;
- }
- else if (timeLeft < scaleTime)
- {
- value *= scaleTime / (scaleTime - timeLeft);
- }
- else
- {
- value = 0.0;
- }
-
- return (F32)(value / scaleTime);
-}
-
-
-U64 LLStatAccum::getCurrentUsecs() const
-{
- if (mUseFrameTimer)
- {
- return LLFrameTimer::getTotalTime();
- }
- else
- {
- return totalTime();
- }
-}
-
-
-// ------------------------------------------------------------------------
-
-LLStatRate::LLStatRate(bool use_frame_timer)
- : LLStatAccum(use_frame_timer)
-{
-}
-
-void LLStatRate::count(U32 value)
-{
- sum((F64)value * sScaleTimes[SCALE_SECOND]);
-}
-
-
-void LLStatRate::mark()
- {
- // Effectively the same as count(1), but sets mLastSampleValue
- U64 when = getCurrentUsecs();
-
- if ( mRunning
- && (when > mLastTime) )
- { // Set mLastSampleValue to the time from the last mark()
- F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND];
- if ( duration > 0.0 )
- {
- mLastSampleValue = 1.0 / duration;
- }
- else
- {
- mLastSampleValue = 0.0;
- }
- }
-
- sum( (F64) sScaleTimes[SCALE_SECOND], when);
- }
-
-
-// ------------------------------------------------------------------------
-
-
-LLStatMeasure::LLStatMeasure(bool use_frame_timer)
- : LLStatAccum(use_frame_timer)
-{
-}
-
-void LLStatMeasure::sample(F64 value)
-{
- U64 when = getCurrentUsecs();
-
- if (mLastSampleValid)
- {
- F64 avgValue = (value + mLastSampleValue) / 2.0;
- F64 interval = (F64)(when - mLastTime);
-
- sum(avgValue * interval, when);
- }
- else
- {
- reset(when);
- }
-
- mLastSampleValid = TRUE;
- mLastSampleValue = value;
-}
-
-
-// ------------------------------------------------------------------------
-
-LLStatTime::LLStatTime(const std::string & key)
- : LLStatAccum(false),
- mFrameNumber(LLFrameTimer::getFrameCount()),
- mTotalTimeInFrame(0),
- mKey(key)
-#if LL_DEBUG
- , mRunning(FALSE)
-#endif
-{
-}
-
-void LLStatTime::start()
-{
- // Reset frame accumluation if the frame number has changed
- U32 frame_number = LLFrameTimer::getFrameCount();
- if ( frame_number != mFrameNumber )
- {
- mFrameNumber = frame_number;
- mTotalTimeInFrame = 0;
- }
-
- sum(0.0);
-
-#if LL_DEBUG
- // Shouldn't be running already
- llassert( !mRunning );
- mRunning = TRUE;
-#endif
-}
-
-void LLStatTime::stop()
-{
- U64 end_time = getCurrentUsecs();
- U64 duration = end_time - mLastTime;
- sum(F64(duration), end_time);
- //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl;
- mTotalTimeInFrame += duration;
-
-#if LL_DEBUG
- mRunning = FALSE;
-#endif
-}
-
-/* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const
-{
- if ( LLStatAccum::SCALE_PER_FRAME == scale )
- {
- return (F32)mTotalTimeInFrame;
- }
- else
- {
- return LLStatAccum::meanValue(scale);
- }
-}
-
-
-// ------------------------------------------------------------------------
-
-
-// Use this constructor for pre-defined LLStatTime objects
-LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL)
-{
- if (mPredefinedStat)
- {
- // If dynamic stats are turned on, this will create a separate entry in the stat map.
- initDynamicStat(mPredefinedStat->mKey);
-
- // Start predefined stats. These stats are not part of the stat map.
- mPredefinedStat->start();
- }
-}
-
-// Use this constructor for normal, optional LLPerfBlock time slices
-LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
-{
- if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
- { // These are off unless the base set is enabled
- return;
- }
-
- initDynamicStat(key);
-}
-
-
-// Use this constructor for dynamically created LLPerfBlock time slices
-// that are only enabled by specific control flags
-LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
-{
- if ((sStatsFlags & flags) == 0)
- {
- return;
- }
-
- if (NULL == key2 || strlen(key2) == 0)
- {
- initDynamicStat(key1);
- }
- else
- {
- std::ostringstream key;
- key << key1 << "_" << key2;
- initDynamicStat(key.str());
- }
-}
-
-// Set up the result data map if dynamic stats are enabled
-void LLPerfBlock::initDynamicStat(const std::string& key)
-{
- // Early exit if dynamic stats aren't enabled.
- if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
- return;
-
- mLastPath = sCurrentStatPath; // Save and restore current path
- sCurrentStatPath += "/" + key; // Add key to current path
-
- // See if the LLStatTime object already exists
- stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath);
- if ( iter == sStatMap.end() )
- {
- // StatEntry object doesn't exist, so create it
- mDynamicStat = new StatEntry( key );
- sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path
- }
- else
- {
- // Found this path in the map, use the object there
- mDynamicStat = (*iter).second; // Get StatEntry for the current path
- }
-
- if (mDynamicStat)
- {
- mDynamicStat->mStat.start();
- mDynamicStat->mCount++;
- }
- else
- {
- llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl;
- sCurrentStatPath = mLastPath;
- }
-}
-
-
-// Destructor does the time accounting
-LLPerfBlock::~LLPerfBlock()
-{
- if (mPredefinedStat) mPredefinedStat->stop();
- if (mDynamicStat)
- {
- mDynamicStat->mStat.stop();
- sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block
- }
-}
-
-
-// Clear the map of any dynamic stats. Static routine
-void LLPerfBlock::clearDynamicStats()
-{
- std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer());
- sStatMap.clear();
-}
-
-// static - Extract the stat info into LLSD
-void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
- LLStatAccum::TimeScale scale )
-{
- // If we aren't in per-frame scale, we need to go from second to microsecond.
- U32 scale_adjustment = 1;
- if (LLStatAccum::SCALE_PER_FRAME != scale)
- {
- scale_adjustment = USEC_PER_SEC;
- }
- stat_map_t::iterator iter = sStatMap.begin();
- for ( ; iter != sStatMap.end(); ++iter )
- { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time
- const std::string & stats_full_path = (*iter).first;
-
- StatEntry * stat = (*iter).second;
- if (stat)
- {
- if (stat->mCount > 0)
- {
- stats[stats_full_path] = LLSD::emptyMap();
- stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale));
- if (stat->mCount > 1)
- {
- stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount;
- }
- stat->mCount = 0;
- }
- }
- else
- { // Shouldn't have a NULL pointer in the map.
- llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
- }
- }
-}
-
-
-// ------------------------------------------------------------------------
-
-LLTimer LLStat::sTimer;
-LLFrameTimer LLStat::sFrameTimer;
-
-void LLStat::init()
-{
- llassert(mNumBins > 0);
- mNumValues = 0;
- mLastValue = 0.f;
- mLastTime = 0.f;
- mCurBin = (mNumBins-1);
- mNextBin = 0;
- mBins = new F32[mNumBins];
- mBeginTime = new F64[mNumBins];
- mTime = new F64[mNumBins];
- mDT = new F32[mNumBins];
- for (U32 i = 0; i < mNumBins; i++)
- {
- mBins[i] = 0.f;
- mBeginTime[i] = 0.0;
- mTime[i] = 0.0;
- mDT[i] = 0.f;
- }
-
- if (!mName.empty())
- {
- stat_map_t::iterator iter = getStatList().find(mName);
- if (iter != getStatList().end())
- llwarns << "LLStat with duplicate name: " << mName << llendl;
- getStatList().insert(std::make_pair(mName, this));
- }
-}
-
-LLStat::stat_map_t& LLStat::getStatList()
-{
- static LLStat::stat_map_t stat_list;
- return stat_list;
-}
-
-LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
- : mUseFrameTimer(use_frame_timer),
- mNumBins(num_bins)
-{
- init();
-}
-
-LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
- : mUseFrameTimer(use_frame_timer),
- mNumBins(num_bins),
- mName(name)
-{
- init();
-}
-
-LLStat::~LLStat()
-{
- delete[] mBins;
- delete[] mBeginTime;
- delete[] mTime;
- delete[] mDT;
-
- if (!mName.empty())
- {
- // handle multiple entries with the same name
- stat_map_t::iterator iter = getStatList().find(mName);
- while (iter != getStatList().end() && iter->second != this)
- ++iter;
- getStatList().erase(iter);
- }
-}
-
-void LLStat::reset()
-{
- U32 i;
-
- mNumValues = 0;
- mLastValue = 0.f;
- mCurBin = (mNumBins-1);
- delete[] mBins;
- delete[] mBeginTime;
- delete[] mTime;
- delete[] mDT;
- mBins = new F32[mNumBins];
- mBeginTime = new F64[mNumBins];
- mTime = new F64[mNumBins];
- mDT = new F32[mNumBins];
- for (i = 0; i < mNumBins; i++)
- {
- mBins[i] = 0.f;
- mBeginTime[i] = 0.0;
- mTime[i] = 0.0;
- mDT[i] = 0.f;
- }
-}
-
-void LLStat::setBeginTime(const F64 time)
-{
- mBeginTime[mNextBin] = time;
-}
-
-void LLStat::addValueTime(const F64 time, const F32 value)
-{
- if (mNumValues < mNumBins)
- {
- mNumValues++;
- }
-
- // Increment the bin counters.
- mCurBin++;
- if ((U32)mCurBin == mNumBins)
- {
- mCurBin = 0;
- }
- mNextBin++;
- if ((U32)mNextBin == mNumBins)
- {
- mNextBin = 0;
- }
-
- mBins[mCurBin] = value;
- mTime[mCurBin] = time;
- mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]);
- //this value is used to prime the min/max calls
- mLastTime = mTime[mCurBin];
- mLastValue = value;
-
- // Set the begin time for the next stat segment.
- mBeginTime[mNextBin] = mTime[mCurBin];
- mTime[mNextBin] = mTime[mCurBin];
- mDT[mNextBin] = 0.f;
-}
-
-void LLStat::start()
-{
- if (mUseFrameTimer)
- {
- mBeginTime[mNextBin] = sFrameTimer.getElapsedSeconds();
- }
- else
- {
- mBeginTime[mNextBin] = sTimer.getElapsedTimeF64();
- }
-}
-
-void LLStat::addValue(const F32 value)
-{
- if (mNumValues < mNumBins)
- {
- mNumValues++;
- }
-
- // Increment the bin counters.
- mCurBin++;
- if ((U32)mCurBin == mNumBins)
- {
- mCurBin = 0;
- }
- mNextBin++;
- if ((U32)mNextBin == mNumBins)
- {
- mNextBin = 0;
- }
-
- mBins[mCurBin] = value;
- if (mUseFrameTimer)
- {
- mTime[mCurBin] = sFrameTimer.getElapsedSeconds();
- }
- else
- {
- mTime[mCurBin] = sTimer.getElapsedTimeF64();
- }
- mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]);
-
- //this value is used to prime the min/max calls
- mLastTime = mTime[mCurBin];
- mLastValue = value;
-
- // Set the begin time for the next stat segment.
- mBeginTime[mNextBin] = mTime[mCurBin];
- mTime[mNextBin] = mTime[mCurBin];
- mDT[mNextBin] = 0.f;
-}
-
-
-F32 LLStat::getMax() const
-{
- U32 i;
- F32 current_max = mLastValue;
- if (mNumBins == 0)
- {
- current_max = 0.f;
- }
- else
- {
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- if (mBins[i] > current_max)
- {
- current_max = mBins[i];
- }
- }
- }
- return current_max;
-}
-
-F32 LLStat::getMean() const
-{
- U32 i;
- F32 current_mean = 0.f;
- U32 samples = 0;
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- current_mean += mBins[i];
- samples++;
- }
-
- // There will be a wrap error at 2^32. :)
- if (samples != 0)
- {
- current_mean /= samples;
- }
- else
- {
- current_mean = 0.f;
- }
- return current_mean;
-}
-
-F32 LLStat::getMin() const
-{
- U32 i;
- F32 current_min = mLastValue;
-
- if (mNumBins == 0)
- {
- current_min = 0.f;
- }
- else
- {
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- if (mBins[i] < current_min)
- {
- current_min = mBins[i];
- }
- }
- }
- return current_min;
-}
-
-F32 LLStat::getSum() const
-{
- U32 i;
- F32 sum = 0.f;
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- sum += mBins[i];
- }
-
- return sum;
-}
-
-F32 LLStat::getSumDuration() const
-{
- U32 i;
- F32 sum = 0.f;
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- sum += mDT[i];
- }
-
- return sum;
-}
-
-F32 LLStat::getPrev(S32 age) const
-{
- S32 bin;
- bin = mCurBin - age;
-
- while (bin < 0)
- {
- bin += mNumBins;
- }
-
- if (bin == mNextBin)
- {
- // Bogus for bin we're currently working on.
- return 0.f;
- }
- return mBins[bin];
-}
-
-F32 LLStat::getPrevPerSec(S32 age) const
-{
- S32 bin;
- bin = mCurBin - age;
-
- while (bin < 0)
- {
- bin += mNumBins;
- }
-
- if (bin == mNextBin)
- {
- // Bogus for bin we're currently working on.
- return 0.f;
- }
- return mBins[bin] / mDT[bin];
-}
-
-F64 LLStat::getPrevBeginTime(S32 age) const
-{
- S32 bin;
- bin = mCurBin - age;
-
- while (bin < 0)
- {
- bin += mNumBins;
- }
-
- if (bin == mNextBin)
- {
- // Bogus for bin we're currently working on.
- return 0.f;
- }
-
- return mBeginTime[bin];
-}
-
-F64 LLStat::getPrevTime(S32 age) const
-{
- S32 bin;
- bin = mCurBin - age;
-
- while (bin < 0)
- {
- bin += mNumBins;
- }
-
- if (bin == mNextBin)
- {
- // Bogus for bin we're currently working on.
- return 0.f;
- }
-
- return mTime[bin];
-}
-
-F32 LLStat::getBin(S32 bin) const
-{
- return mBins[bin];
-}
-
-F32 LLStat::getBinPerSec(S32 bin) const
-{
- return mBins[bin] / mDT[bin];
-}
-
-F64 LLStat::getBinBeginTime(S32 bin) const
-{
- return mBeginTime[bin];
-}
-
-F64 LLStat::getBinTime(S32 bin) const
-{
- return mTime[bin];
-}
-
-F32 LLStat::getCurrent() const
-{
- return mBins[mCurBin];
-}
-
-F32 LLStat::getCurrentPerSec() const
-{
- return mBins[mCurBin] / mDT[mCurBin];
-}
-
-F64 LLStat::getCurrentBeginTime() const
-{
- return mBeginTime[mCurBin];
-}
-
-F64 LLStat::getCurrentTime() const
-{
- return mTime[mCurBin];
-}
-
-F32 LLStat::getCurrentDuration() const
-{
- return mDT[mCurBin];
-}
-
-F32 LLStat::getMeanPerSec() const
-{
- U32 i;
- F32 value = 0.f;
- F32 dt = 0.f;
-
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- value += mBins[i];
- dt += mDT[i];
- }
-
- if (dt > 0.f)
- {
- return value/dt;
- }
- else
- {
- return 0.f;
- }
-}
-
-F32 LLStat::getMeanDuration() const
-{
- F32 dur = 0.0f;
- U32 count = 0;
- for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++)
- {
- if (i == (U32)mNextBin)
- {
- continue;
- }
- dur += mDT[i];
- count++;
- }
-
- if (count > 0)
- {
- dur /= F32(count);
- return dur;
- }
- else
- {
- return 0.f;
- }
-}
-
-F32 LLStat::getMaxPerSec() const
-{
- U32 i;
- F32 value;
-
- if (mNextBin != 0)
- {
- value = mBins[0]/mDT[0];
- }
- else if (mNumValues > 0)
- {
- value = mBins[1]/mDT[1];
- }
- else
- {
- value = 0.f;
- }
-
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- value = llmax(value, mBins[i]/mDT[i]);
- }
- return value;
-}
-
-F32 LLStat::getMinPerSec() const
-{
- U32 i;
- F32 value;
-
- if (mNextBin != 0)
- {
- value = mBins[0]/mDT[0];
- }
- else if (mNumValues > 0)
- {
- value = mBins[1]/mDT[1];
- }
- else
- {
- value = 0.f;
- }
-
- for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
- {
- // Skip the bin we're currently filling.
- if (i == (U32)mNextBin)
- {
- continue;
- }
- value = llmin(value, mBins[i]/mDT[i]);
- }
- return value;
-}
-
-F32 LLStat::getMinDuration() const
-{
- F32 dur = 0.0f;
- for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++)
- {
- dur = llmin(dur, mDT[i]);
- }
- return dur;
-}
-
-U32 LLStat::getNumValues() const
-{
- return mNumValues;
-}
-
-S32 LLStat::getNumBins() const
-{
- return mNumBins;
-}
-
-S32 LLStat::getCurBin() const
-{
- return mCurBin;
-}
-
-S32 LLStat::getNextBin() const
-{
- return mNextBin;
-}
-
-F64 LLStat::getLastTime() const
-{
- return mLastTime;
-}
diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h
deleted file mode 100644
index 1a8404cc07..0000000000
--- a/indra/llcommon/llstat.h
+++ /dev/null
@@ -1,353 +0,0 @@
-/**
- * @file llstat.h
- * @brief Runtime statistics accumulation.
- *
- * $LicenseInfo:firstyear=2001&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_LLSTAT_H
-#define LL_LLSTAT_H
-
-#include <deque>
-#include <map>
-
-#include "lltimer.h"
-#include "llframetimer.h"
-#include "llfile.h"
-
-class LLSD;
-
-// Set this if longer stats are needed
-#define ENABLE_LONG_TIME_STATS 0
-
-//
-// Accumulates statistics for an arbitrary length of time.
-// Does this by maintaining a chain of accumulators, each one
-// accumulation the results of the parent. Can scale to arbitrary
-// amounts of time with very low memory cost.
-//
-
-class LL_COMMON_API LLStatAccum
-{
-protected:
- LLStatAccum(bool use_frame_timer);
- virtual ~LLStatAccum();
-
-public:
- enum TimeScale {
- SCALE_100MS,
- SCALE_SECOND,
- SCALE_MINUTE,
-#if ENABLE_LONG_TIME_STATS
- SCALE_HOUR,
- SCALE_DAY,
- SCALE_WEEK,
-#endif
- NUM_SCALES, // Use to size storage arrays
- SCALE_PER_FRAME // For latest frame information - should be after NUM_SCALES since this doesn't go into the time buckets
- };
-
- static U64 sScaleTimes[NUM_SCALES];
-
- virtual F32 meanValue(TimeScale scale) const;
- // see the subclasses for the specific meaning of value
-
- F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); }
- F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); }
- F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); }
-
- void reset(U64 when);
-
- void sum(F64 value);
- void sum(F64 value, U64 when);
-
- U64 getCurrentUsecs() const;
- // Get current microseconds based on timer type
-
- BOOL mUseFrameTimer;
- BOOL mRunning;
-
- U64 mLastTime;
-
- struct Bucket
- {
- Bucket() :
- accum(0.0),
- endTime(0),
- lastValid(false),
- lastAccum(0.0)
- {}
-
- F64 accum;
- U64 endTime;
-
- bool lastValid;
- F64 lastAccum;
- };
-
- Bucket mBuckets[NUM_SCALES];
-
- BOOL mLastSampleValid;
- F64 mLastSampleValue;
-};
-
-class LL_COMMON_API LLStatMeasure : public LLStatAccum
- // gathers statistics about things that are measured
- // ex.: tempature, time dilation
-{
-public:
- LLStatMeasure(bool use_frame_timer = true);
-
- void sample(F64);
- void sample(S32 v) { sample((F64)v); }
- void sample(U32 v) { sample((F64)v); }
- void sample(S64 v) { sample((F64)v); }
- void sample(U64 v) { sample((F64)v); }
-};
-
-
-class LL_COMMON_API LLStatRate : public LLStatAccum
- // gathers statistics about things that can be counted over time
- // ex.: LSL instructions executed, messages sent, simulator frames completed
- // renders it in terms of rate of thing per second
-{
-public:
- LLStatRate(bool use_frame_timer = true);
-
- void count(U32);
- // used to note that n items have occured
-
- void mark();
- // used for counting the rate thorugh a point in the code
-};
-
-
-class LL_COMMON_API LLStatTime : public LLStatAccum
- // gathers statistics about time spent in a block of code
- // measure average duration per second in the block
-{
-public:
- LLStatTime( const std::string & key = "undefined" );
-
- U32 mFrameNumber; // Current frame number
- U64 mTotalTimeInFrame; // Total time (microseconds) accumulated during the last frame
-
- void setKey( const std::string & key ) { mKey = key; };
-
- virtual F32 meanValue(TimeScale scale) const;
-
-private:
- void start(); // Start and stop measuring time block
- void stop();
-
- std::string mKey; // Tag representing this time block
-
-#if LL_DEBUG
- BOOL mRunning; // TRUE if start() has been called
-#endif
-
- friend class LLPerfBlock;
-};
-
-// ----------------------------------------------------------------------------
-
-
-// Use this class on the stack to record statistics about an area of code
-class LL_COMMON_API LLPerfBlock
-{
-public:
- struct StatEntry
- {
- StatEntry(const std::string& key) : mStat(LLStatTime(key)), mCount(0) {}
- LLStatTime mStat;
- U32 mCount;
- };
- typedef std::map<std::string, StatEntry*> stat_map_t;
-
- // Use this constructor for pre-defined LLStatTime objects
- LLPerfBlock(LLStatTime* stat);
-
- // Use this constructor for normal, optional LLPerfBlock time slices
- LLPerfBlock( const char* key );
-
- // Use this constructor for dynamically created LLPerfBlock time slices
- // that are only enabled by specific control flags
- LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
-
- ~LLPerfBlock();
-
- enum
- { // Stats bitfield flags
- LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
- LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
- LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
- };
- static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
- static S32 getStatsFlags() { return sStatsFlags; };
-
- static void clearDynamicStats(); // Reset maps to clear out dynamic objects
- static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
- LLStatAccum::TimeScale scale );
-
-private:
- // Initialize dynamically created LLStatTime objects
- void initDynamicStat(const std::string& key);
-
- std::string mLastPath; // Save sCurrentStatPath when this is called
- LLStatTime * mPredefinedStat; // LLStatTime object to get data
- StatEntry * mDynamicStat; // StatEntryobject to get data
-
- static S32 sStatsFlags; // Control what is being recorded
- static stat_map_t sStatMap; // Map full path string to LLStatTime objects
- static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
-};
-
-// ----------------------------------------------------------------------------
-
-class LL_COMMON_API LLPerfStats
-{
-public:
- LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0);
- virtual ~LLPerfStats();
-
- virtual void init(); // Reset and start all stat timers
- virtual void updatePerFrameStats();
- // Override these function to add process-specific information to the performance log header and per-frame logging.
- virtual void addProcessHeaderInfo(LLSD& info) { /* not implemented */ }
- virtual void addProcessFrameInfo(LLSD& info, LLStatAccum::TimeScale scale) { /* not implemented */ }
-
- // High-resolution frame stats
- BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
- F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
- void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
- void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
- void setProcessName(const std::string& process_name) { mProcessName = process_name; }
- void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
-
-protected:
- void openPerfStatsFile(); // Open file for high resolution metrics logging
- void dumpIntervalPerformanceStats();
-
- llofstream mFrameStatsFile; // File for per-frame stats
- BOOL mFrameStatsFileFailure; // Flag to prevent repeat opening attempts
- BOOL mSkipFirstFrameStats; // Flag to skip one (partial) frame report
- std::string mProcessName;
- S32 mProcessPID;
-
-private:
- F32 mReportPerformanceStatInterval; // Seconds between performance stats
- F64 mReportPerformanceStatEnd; // End time (seconds) for performance stats
-};
-
-// ----------------------------------------------------------------------------
-class LL_COMMON_API LLStat
-{
-private:
- typedef std::multimap<std::string, LLStat*> stat_map_t;
-
- void init();
- static stat_map_t& getStatList();
-
-public:
- LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
- LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
- ~LLStat();
-
- void reset();
-
- void start(); // Start the timer for the current "frame", otherwise uses the time tracked from
- // the last addValue
- void addValue(const F32 value = 1.f); // Adds the current value being tracked, and tracks the DT.
- void addValue(const S32 value) { addValue((F32)value); }
- void addValue(const U32 value) { addValue((F32)value); }
-
- void setBeginTime(const F64 time);
- void addValueTime(const F64 time, const F32 value = 1.f);
-
- S32 getCurBin() const;
- S32 getNextBin() const;
-
- F32 getCurrent() const;
- F32 getCurrentPerSec() const;
- F64 getCurrentBeginTime() const;
- F64 getCurrentTime() const;
- F32 getCurrentDuration() const;
-
- F32 getPrev(S32 age) const; // Age is how many "addValues" previously - zero is current
- F32 getPrevPerSec(S32 age) const; // Age is how many "addValues" previously - zero is current
- F64 getPrevBeginTime(S32 age) const;
- F64 getPrevTime(S32 age) const;
-
- F32 getBin(S32 bin) const;
- F32 getBinPerSec(S32 bin) const;
- F64 getBinBeginTime(S32 bin) const;
- F64 getBinTime(S32 bin) const;
-
- F32 getMax() const;
- F32 getMaxPerSec() const;
-
- F32 getMean() const;
- F32 getMeanPerSec() const;
- F32 getMeanDuration() const;
-
- F32 getMin() const;
- F32 getMinPerSec() const;
- F32 getMinDuration() const;
-
- F32 getSum() const;
- F32 getSumDuration() const;
-
- U32 getNumValues() const;
- S32 getNumBins() const;
-
- F64 getLastTime() const;
-private:
- BOOL mUseFrameTimer;
- U32 mNumValues;
- U32 mNumBins;
- F32 mLastValue;
- F64 mLastTime;
- F32 *mBins;
- F64 *mBeginTime;
- F64 *mTime;
- F32 *mDT;
- S32 mCurBin;
- S32 mNextBin;
-
- std::string mName;
-
- static LLTimer sTimer;
- static LLFrameTimer sFrameTimer;
-
-public:
- static LLStat* getStat(const std::string& name)
- {
- // return the first stat that matches 'name'
- stat_map_t::iterator iter = getStatList().find(name);
- if (iter != getStatList().end())
- return iter->second;
- else
- return NULL;
- }
-};
-
-#endif // LL_STAT_
diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h
index 81c4085d16..ab9b6709e8 100644
--- a/indra/llcommon/llstatenums.h
+++ b/indra/llcommon/llstatenums.h
@@ -26,7 +26,7 @@
#ifndef LL_LLSTATENUMS_H
#define LL_LLSTATENUMS_H
-enum
+enum ESimStatID
{
LL_SIM_STAT_TIME_DILATION = 0,
LL_SIM_STAT_FPS = 1,
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index d3941e1bc9..424138dad1 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -31,6 +31,7 @@
#include <algorithm>
#include <map>
#include <vector>
+#include <list>
#include <set>
#include <deque>
#include <typeinfo>
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 0c32679744..67bbc58bf5 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -28,11 +28,10 @@
#include "llstring.h"
#include "llerror.h"
+#include "llfasttimer.h"
#if LL_WINDOWS
-#define WIN32_LEAN_AND_MEAN
-#include <winsock2.h>
-#include <windows.h>
+#include "llwin32headerslean.h"
#include <winnls.h> // for WideCharToMultiByte
#endif
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 119efc7957..9d81ac25dd 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -31,8 +31,9 @@
#include <cstdio>
#include <locale>
#include <iomanip>
+#include <algorithm>
#include "llsd.h"
-#include "llfasttimer.h"
+#include "llformat.h"
#if LL_LINUX || LL_SOLARIS
#include <wctype.h>
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index c96f2191f3..d6fe648b42 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -42,6 +42,7 @@
#include "llprocessor.h"
#include "llerrorcontrol.h"
#include "llevents.h"
+#include "llformat.h"
#include "lltimer.h"
#include "llsdserialize.h"
#include "llsdutil.h"
@@ -58,9 +59,7 @@
using namespace llsd;
#if LL_WINDOWS
-# define WIN32_LEAN_AND_MEAN
-# include <winsock2.h>
-# include <windows.h>
+# include "llwin32headerslean.h"
# include <psapi.h> // GetPerformanceInfo() et al.
#elif LL_DARWIN
# include <errno.h>
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 1d56a52c32..6374b5398b 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -29,8 +29,11 @@
#include "apr_portable.h"
#include "llthread.h"
+#include "llmutex.h"
#include "lltimer.h"
+#include "lltrace.h"
+#include "lltracethreadrecorder.h"
#if LL_LINUX || LL_SOLARIS
#include <sched.h>
@@ -56,12 +59,17 @@
//
//----------------------------------------------------------------------------
-#if !LL_DARWIN
-U32 ll_thread_local sThreadID = 0;
+#if LL_DARWIN
+// statically allocated thread local storage not supported in Darwin executable formats
+#elif LL_WINDOWS
+U32 __declspec(thread) sThreadID = 0;
+#elif LL_LINUX
+U32 __thread sThreadID = 0;
#endif
U32 LLThread::sIDIter = 0;
+
LL_COMMON_API void assert_main_thread()
{
static U32 s_thread_id = LLThread::currentID();
@@ -85,6 +93,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
{
LLThread *threadp = (LLThread *)datap;
+ LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder();
+
#if !LL_DARWIN
sThreadID = threadp->mID;
#endif
@@ -97,16 +107,18 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
// We're done with the run function, this thread is done executing now.
threadp->mStatus = STOPPED;
+ delete thread_recorder;
+
return NULL;
}
-
LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
mPaused(FALSE),
mName(name),
mAPRThreadp(NULL),
mStatus(STOPPED)
{
+
mID = ++sIDIter;
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
@@ -152,7 +164,7 @@ void LLThread::shutdown()
//llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
// Now wait a bit for the thread to exit
// It's unclear whether I should even bother doing this - this destructor
- // should netver get called unless we're already stopped, really...
+ // should never get called unless we're already stopped, really...
S32 counter = 0;
const S32 MAX_WAIT = 600;
while (counter < MAX_WAIT)
@@ -282,7 +294,13 @@ void LLThread::setQuitting()
// static
U32 LLThread::currentID()
{
+#if LL_DARWIN
+ // statically allocated thread local storage not supported in Darwin executable formats
return (U32)apr_os_thread_current();
+#else
+ return sThreadID;
+#endif
+
}
// static
@@ -315,155 +333,6 @@ void LLThread::wakeLocked()
//============================================================================
-LLMutex::LLMutex(apr_pool_t *poolp) :
- mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
-{
- //if (poolp)
- //{
- // mIsLocalPool = FALSE;
- // mAPRPoolp = poolp;
- //}
- //else
- {
- mIsLocalPool = TRUE;
- apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
- }
- apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
-}
-
-
-LLMutex::~LLMutex()
-{
-#if MUTEX_DEBUG
- //bad assertion, the subclass LLSignal might be "locked", and that's OK
- //llassert_always(!isLocked()); // better not be locked!
-#endif
- apr_thread_mutex_destroy(mAPRMutexp);
- mAPRMutexp = NULL;
- if (mIsLocalPool)
- {
- apr_pool_destroy(mAPRPoolp);
- }
-}
-
-
-void LLMutex::lock()
-{
- if(isSelfLocked())
- { //redundant lock
- mCount++;
- return;
- }
-
- apr_thread_mutex_lock(mAPRMutexp);
-
-#if MUTEX_DEBUG
- // Have to have the lock before we can access the debug info
- U32 id = LLThread::currentID();
- if (mIsLocked[id] != FALSE)
- llerrs << "Already locked in Thread: " << id << llendl;
- mIsLocked[id] = TRUE;
-#endif
-
-#if LL_DARWIN
- mLockingThread = LLThread::currentID();
-#else
- mLockingThread = sThreadID;
-#endif
-}
-
-void LLMutex::unlock()
-{
- if (mCount > 0)
- { //not the root unlock
- mCount--;
- return;
- }
-
-#if MUTEX_DEBUG
- // Access the debug info while we have the lock
- U32 id = LLThread::currentID();
- if (mIsLocked[id] != TRUE)
- llerrs << "Not locked in Thread: " << id << llendl;
- mIsLocked[id] = FALSE;
-#endif
-
- mLockingThread = NO_THREAD;
- apr_thread_mutex_unlock(mAPRMutexp);
-}
-
-bool LLMutex::isLocked()
-{
- apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
- if (APR_STATUS_IS_EBUSY(status))
- {
- return true;
- }
- else
- {
- apr_thread_mutex_unlock(mAPRMutexp);
- return false;
- }
-}
-
-bool LLMutex::isSelfLocked()
-{
-#if LL_DARWIN
- return mLockingThread == LLThread::currentID();
-#else
- return mLockingThread == sThreadID;
-#endif
-}
-
-U32 LLMutex::lockingThread() const
-{
- return mLockingThread;
-}
-
-//============================================================================
-
-LLCondition::LLCondition(apr_pool_t *poolp) :
- LLMutex(poolp)
-{
- // base class (LLMutex) has already ensured that mAPRPoolp is set up.
-
- apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
-}
-
-
-LLCondition::~LLCondition()
-{
- apr_thread_cond_destroy(mAPRCondp);
- mAPRCondp = NULL;
-}
-
-
-void LLCondition::wait()
-{
- if (!isLocked())
- { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
- apr_thread_mutex_lock(mAPRMutexp);
-#if MUTEX_DEBUG
- // avoid asserts on destruction in non-release builds
- U32 id = LLThread::currentID();
- mIsLocked[id] = TRUE;
-#endif
- }
- apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
-}
-
-void LLCondition::signal()
-{
- apr_thread_cond_signal(mAPRCondp);
-}
-
-void LLCondition::broadcast()
-{
- apr_thread_cond_broadcast(mAPRCondp);
-}
-
-//============================================================================
-
//----------------------------------------------------------------------------
//static
@@ -514,7 +383,6 @@ LLThreadSafeRefCount::~LLThreadSafeRefCount()
}
}
-
//============================================================================
LLResponder::~LLResponder()
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 5c8bbca2ca..92323f5fda 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -30,20 +30,14 @@
#include "llapp.h"
#include "llapr.h"
#include "apr_thread_cond.h"
+#include "llmutex.h"
-class LLThread;
-class LLMutex;
-class LLCondition;
-
-#if LL_WINDOWS
-#define ll_thread_local __declspec(thread)
-#else
-#define ll_thread_local __thread
-#endif
+LL_COMMON_API void assert_main_thread();
class LL_COMMON_API LLThread
{
private:
+ friend class LLMutex;
static U32 sIDIter;
public:
@@ -101,7 +95,7 @@ private:
protected:
std::string mName;
- LLCondition* mRunCondition;
+ class LLCondition* mRunCondition;
LLMutex* mDataLock;
apr_thread_t *mAPRThreadp;
@@ -139,75 +133,6 @@ protected:
// mDataLock->unlock();
};
-//============================================================================
-
-#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
-
-class LL_COMMON_API LLMutex
-{
-public:
- typedef enum
- {
- NO_THREAD = 0xFFFFFFFF
- } e_locking_thread;
-
- LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
- virtual ~LLMutex();
-
- void lock(); // blocks
- void unlock();
- bool isLocked(); // non-blocking, but does do a lock/unlock so not free
- bool isSelfLocked(); //return true if locked in a same thread
- U32 lockingThread() const; //get ID of locking thread
-
-protected:
- apr_thread_mutex_t *mAPRMutexp;
- mutable U32 mCount;
- mutable U32 mLockingThread;
-
- apr_pool_t *mAPRPoolp;
- BOOL mIsLocalPool;
-
-#if MUTEX_DEBUG
- std::map<U32, BOOL> mIsLocked;
-#endif
-};
-
-// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
-class LL_COMMON_API LLCondition : public LLMutex
-{
-public:
- LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
- ~LLCondition();
-
- void wait(); // blocks
- void signal();
- void broadcast();
-
-protected:
- apr_thread_cond_t *mAPRCondp;
-};
-
-class LLMutexLock
-{
-public:
- LLMutexLock(LLMutex* mutex)
- {
- mMutex = mutex;
-
- if(mMutex)
- mMutex->lock();
- }
- ~LLMutexLock()
- {
- if(mMutex)
- mMutex->unlock();
- }
-private:
- LLMutex* mMutex;
-};
-
-//============================================================================
void LLThread::lockData()
{
diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h
new file mode 100644
index 0000000000..5a38d54eea
--- /dev/null
+++ b/indra/llcommon/llthreadlocalstorage.h
@@ -0,0 +1,275 @@
+/**
+ * @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() {}
+
+#ifdef LL_WINDOWS
+ static __declspec(thread) DERIVED_TYPE* sInstance;
+ static __declspec(thread) EInitState sInitState;
+#elif LL_LINUX
+ static __thread DERIVED_TYPE* sInstance;
+ static __thread EInitState sInitState;
+#endif
+};
+
+#ifdef LL_WINDOWS
+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;
+#elif LL_LINUX
+template<typename DERIVED_TYPE>
+__thread DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
+
+template<typename DERIVED_TYPE>
+__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
+#endif
+
+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:
+#ifdef LL_WINDOWS
+ static __declspec(thread) DERIVED_TYPE* sInstance;
+#elif LL_LINUX
+ static __thread DERIVED_TYPE* sInstance;
+#endif
+};
+
+template<typename DERIVED_TYPE>
+#ifdef LL_WINDOWS
+__declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL;
+#elif LL_LINUX
+__thread DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL;
+#endif
+
+#endif // LL_LLTHREADLOCALSTORAGE_H
diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp
index 9ebc6de7f4..838155d54d 100644
--- a/indra/llcommon/lltimer.cpp
+++ b/indra/llcommon/lltimer.cpp
@@ -31,11 +31,9 @@
#include "u64.h"
#if LL_WINDOWS
-# define WIN32_LEAN_AND_MEAN
-# include <winsock2.h>
-# include <windows.h>
+# include "llwin32headerslean.h"
#elif LL_LINUX || LL_SOLARIS || LL_DARWIN
-# include <errno.h>
+# include <errno.h>
# include <sys/time.h>
#else
# error "architecture not supported"
@@ -287,14 +285,14 @@ LLTimer::~LLTimer()
}
// static
-U64 LLTimer::getTotalTime()
+LLUnitImplicit<LLUnits::Microseconds, U64> LLTimer::getTotalTime()
{
// simply call into the implementation function.
return totalTime();
}
// static
-F64 LLTimer::getTotalSeconds()
+LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getTotalSeconds()
{
return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;
}
@@ -343,23 +341,23 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount)
}
-F64 LLTimer::getElapsedTimeF64() const
+LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeF64() const
{
U64 last = mLastClockCount;
return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;
}
-F32 LLTimer::getElapsedTimeF32() const
+LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeF32() const
{
return (F32)getElapsedTimeF64();
}
-F64 LLTimer::getElapsedTimeAndResetF64()
+LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeAndResetF64()
{
return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;
}
-F32 LLTimer::getElapsedTimeAndResetF32()
+LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeAndResetF32()
{
return (F32)getElapsedTimeAndResetF64();
}
@@ -372,7 +370,7 @@ void LLTimer::setTimerExpirySec(F32 expiration)
+ (U64)((F32)(expiration * gClockFrequency));
}
-F32 LLTimer::getRemainingTimeF32() const
+LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getRemainingTimeF32() const
{
U64 cur_ticks = get_clock_count();
if (cur_ticks > mExpirationTicks)
diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h
index 513de0605d..0ba87d1e15 100644
--- a/indra/llcommon/lltimer.h
+++ b/indra/llcommon/lltimer.h
@@ -37,6 +37,7 @@
#include <string>
#include <list>
// units conversions
+#include "llunit.h"
#ifndef USEC_PER_SEC
const U32 USEC_PER_SEC = 1000000;
#endif
@@ -55,7 +56,7 @@ public:
protected:
U64 mLastClockCount;
U64 mExpirationTicks;
- BOOL mStarted;
+ bool mStarted;
public:
LLTimer();
@@ -66,16 +67,16 @@ public:
// Return a high precision number of seconds since the start of
// this application instance.
- static F64 getElapsedSeconds()
+ static LLUnitImplicit<LLUnits::Seconds, F64> getElapsedSeconds()
{
return sTimer->getElapsedTimeF64();
}
// Return a high precision usec since epoch
- static U64 getTotalTime();
+ static LLUnitImplicit<LLUnits::Microseconds, U64> getTotalTime();
// Return a high precision seconds since epoch
- static F64 getTotalSeconds();
+ static LLUnitImplicit<LLUnits::Seconds, F64> getTotalSeconds();
// MANIPULATORS
@@ -86,18 +87,18 @@ public:
void setTimerExpirySec(F32 expiration);
BOOL checkExpirationAndReset(F32 expiration);
BOOL hasExpired() const;
- F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
- F64 getElapsedTimeAndResetF64();
+ LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
+ LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeAndResetF64();
- F32 getRemainingTimeF32() const;
+ LLUnitImplicit<LLUnits::Seconds, F32> getRemainingTimeF32() const;
static BOOL knownBadTimer();
// ACCESSORS
- F32 getElapsedTimeF32() const; // Returns elapsed time in seconds
- F64 getElapsedTimeF64() const; // Returns elapsed time in seconds
+ LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeF32() const; // Returns elapsed time in seconds
+ LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeF64() const; // Returns elapsed time in seconds
- BOOL getStarted() const { return mStarted; }
+ bool getStarted() const { return mStarted; }
static U64 getCurrentClockCount(); // Returns the raw clockticks
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
new file mode 100644
index 0000000000..9cadd70dd8
--- /dev/null
+++ b/indra/llcommon/lltrace.cpp
@@ -0,0 +1,110 @@
+/**
+ * @file lltrace.cpp
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#include "linden_common.h"
+
+#include "lltrace.h"
+#include "lltracerecording.h"
+#include "lltracethreadrecorder.h"
+#include "llfasttimer.h"
+
+static bool sInitialized;
+
+namespace LLTrace
+{
+
+static MasterThreadRecorder* gMasterThreadRecorder = NULL;
+
+void init()
+{
+ gMasterThreadRecorder = new MasterThreadRecorder();
+ sInitialized = true;
+}
+
+bool isInitialized()
+{
+ return sInitialized;
+}
+
+void cleanup()
+{
+ delete gMasterThreadRecorder;
+ gMasterThreadRecorder = NULL;
+}
+
+MasterThreadRecorder& getMasterThreadRecorder()
+{
+ llassert(gMasterThreadRecorder != NULL);
+ return *gMasterThreadRecorder;
+}
+
+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),
+ mNeedsSorting(false)
+{}
+
+void TimeBlockTreeNode::setParent( TimeBlock* parent )
+{
+ llassert_always(parent != mBlock);
+ llassert_always(parent != NULL);
+
+ TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(parent->getIndex());
+ if (!parent_tree_node) return;
+
+ if (mParent)
+ {
+ std::vector<TimeBlock*>& children = mParent->getChildren();
+ std::vector<TimeBlock*>::iterator found_it = std::find(children.begin(), children.end(), mBlock);
+ if (found_it != children.end())
+ {
+ children.erase(found_it);
+ }
+ }
+
+ mParent = parent;
+ mBlock->getPrimaryAccumulator()->mParent = parent;
+ parent_tree_node->mChildren.push_back(mBlock);
+ parent_tree_node->mNeedsSorting = true;
+}
+
+}
diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h
new file mode 100644
index 0000000000..1a156e583e
--- /dev/null
+++ b/indra/llcommon/lltrace.h
@@ -0,0 +1,836 @@
+/**
+ * @file lltrace.h
+ * @brief Runtime statistics accumulation.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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_LLTRACE_H
+#define LL_LLTRACE_H
+
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+
+#include "llmemory.h"
+#include "llrefcount.h"
+#include "llunit.h"
+#include "llapr.h"
+#include "llthreadlocalstorage.h"
+
+#include <list>
+
+#define LL_RECORD_BLOCK_TIME(block_timer) LLTrace::TimeBlock::Recorder LL_GLUE_TOKENS(block_time_recorder, __COUNTER__)(block_timer);
+
+namespace LLTrace
+{
+ class Recording;
+
+ typedef LLUnit<LLUnits::Bytes, F64> Bytes;
+ typedef LLUnit<LLUnits::Kilobytes, F64> Kilobytes;
+ typedef LLUnit<LLUnits::Megabytes, F64> Megabytes;
+ typedef LLUnit<LLUnits::Gigabytes, F64> Gigabytes;
+ typedef LLUnit<LLUnits::Bits, F64> Bits;
+ typedef LLUnit<LLUnits::Kilobits, F64> Kilobits;
+ typedef LLUnit<LLUnits::Megabits, F64> Megabits;
+ typedef LLUnit<LLUnits::Gigabits, F64> Gigabits;
+
+ typedef LLUnit<LLUnits::Seconds, F64> Seconds;
+ typedef LLUnit<LLUnits::Milliseconds, F64> Milliseconds;
+ typedef LLUnit<LLUnits::Minutes, F64> Minutes;
+ typedef LLUnit<LLUnits::Hours, F64> Hours;
+ typedef LLUnit<LLUnits::Milliseconds, F64> Milliseconds;
+ typedef LLUnit<LLUnits::Microseconds, F64> Microseconds;
+ typedef LLUnit<LLUnits::Nanoseconds, F64> Nanoseconds;
+
+ typedef LLUnit<LLUnits::Meters, F64> Meters;
+ typedef LLUnit<LLUnits::Kilometers, F64> Kilometers;
+ typedef LLUnit<LLUnits::Centimeters, F64> Centimeters;
+ typedef LLUnit<LLUnits::Millimeters, F64> Millimeters;
+
+ void init();
+ void cleanup();
+ bool isInitialized();
+
+ const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder();
+ void set_thread_recorder(class ThreadRecorder*);
+
+ class MasterThreadRecorder& getMasterThreadRecorder();
+
+ // one per thread per type
+ template<typename ACCUMULATOR>
+ class AccumulatorBuffer : public LLRefCount
+ {
+ typedef AccumulatorBuffer<ACCUMULATOR> self_t;
+ static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
+ private:
+ struct StaticAllocationMarker { };
+
+ AccumulatorBuffer(StaticAllocationMarker m)
+ : mStorageSize(0),
+ mStorage(NULL),
+ mNextStorageSlot(0)
+ {
+ }
+
+ public:
+
+ AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer())
+ : mStorageSize(0),
+ mStorage(NULL),
+ mNextStorageSlot(other.mNextStorageSlot)
+ {
+ resize(other.mStorageSize);
+ for (S32 i = 0; i < mNextStorageSlot; i++)
+ {
+ mStorage[i] = other.mStorage[i];
+ }
+ }
+
+ ~AccumulatorBuffer()
+ {
+ if (LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage)
+ {
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(getDefaultBuffer()->mStorage);
+ }
+ delete[] mStorage;
+ }
+
+ LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index)
+ {
+ return mStorage[index];
+ }
+
+ LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const
+ {
+ return mStorage[index];
+ }
+
+ void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other)
+ {
+ llassert(mNextStorageSlot == other.mNextStorageSlot);
+
+ for (size_t i = 0; i < mNextStorageSlot; i++)
+ {
+ mStorage[i].addSamples(other.mStorage[i]);
+ }
+ }
+
+ void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
+ {
+ for (size_t i = 0; i < mNextStorageSlot; i++)
+ {
+ mStorage[i] = other.mStorage[i];
+ }
+ }
+
+ void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
+ {
+ for (size_t i = 0; i < mNextStorageSlot; i++)
+ {
+ mStorage[i].reset(other ? &other->mStorage[i] : NULL);
+ }
+ }
+
+ void makePrimary()
+ {
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage);
+ }
+
+ bool isPrimary() const
+ {
+ return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;
+ }
+
+ LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()
+ {
+ 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
+ size_t reserveSlot()
+ {
+ if (LLTrace::isInitialized())
+ {
+ llerrs << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << llendl;
+ }
+ size_t next_slot = mNextStorageSlot++;
+ if (next_slot >= mStorageSize)
+ {
+ resize(mStorageSize + (mStorageSize >> 2));
+ }
+ llassert(mStorage && next_slot < mStorageSize);
+ return next_slot;
+ }
+
+ void resize(size_t new_size)
+ {
+ if (new_size <= mStorageSize) return;
+
+ ACCUMULATOR* old_storage = mStorage;
+ mStorage = new ACCUMULATOR[new_size];
+ if (old_storage)
+ {
+ for (S32 i = 0; i < mStorageSize; i++)
+ {
+ mStorage[i] = old_storage[i];
+ }
+ }
+ mStorageSize = new_size;
+ delete[] old_storage;
+
+ self_t* default_buffer = getDefaultBuffer();
+ if (this != default_buffer
+ && new_size > default_buffer->size())
+ {
+ //NB: this is not thread safe, but we assume that all resizing occurs during static initialization
+ default_buffer->resize(new_size);
+ }
+ }
+
+ size_t size() const
+ {
+ return mNextStorageSlot;
+ }
+
+ static self_t* getDefaultBuffer()
+ {
+ // 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
+ static self_t* sBuffer = new AccumulatorBuffer(StaticAllocationMarker());
+ static bool sInitialized = false;
+ if (!sInitialized)
+ {
+ sBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE);
+ sInitialized = true;
+ }
+ return sBuffer;
+ }
+
+ private:
+ ACCUMULATOR* mStorage;
+ size_t mStorageSize;
+ size_t mNextStorageSlot;
+ };
+
+ //TODO: replace with decltype when C++11 is enabled
+ template<typename T>
+ struct MeanValueType
+ {
+ typedef F64 type;
+ };
+
+ template<typename ACCUMULATOR>
+ class TraceType
+ : public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>
+ {
+ public:
+ typedef typename MeanValueType<TraceType<ACCUMULATOR> >::type mean_t;
+
+ TraceType(const char* name, const char* description = NULL)
+ : LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>(name),
+ mName(name),
+ mDescription(description ? description : ""),
+ mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot())
+ {}
+
+ LL_FORCE_INLINE ACCUMULATOR* getPrimaryAccumulator() const
+ {
+ ACCUMULATOR* accumulator_storage = AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage();
+ return &accumulator_storage[mAccumulatorIndex];
+ }
+
+ size_t getIndex() const { return mAccumulatorIndex; }
+
+ const std::string& getName() const { return mName; }
+
+ protected:
+ const std::string mName;
+ const std::string mDescription;
+ const size_t mAccumulatorIndex;
+ };
+
+ template<typename T>
+ class MeasurementAccumulator
+ {
+ public:
+ typedef T value_t;
+ typedef MeasurementAccumulator<T> self_t;
+
+ MeasurementAccumulator()
+ : mSum(0),
+ mMin((std::numeric_limits<T>::max)()),
+ mMax((std::numeric_limits<T>::min)()),
+ mMean(0),
+ mVarianceSum(0),
+ mNumSamples(0),
+ mLastValue(0)
+ {}
+
+ LL_FORCE_INLINE void sample(T value)
+ {
+ T storage_value(value);
+ mNumSamples++;
+ mSum += storage_value;
+ if (storage_value < mMin)
+ {
+ mMin = storage_value;
+ }
+ if (storage_value > mMax)
+ {
+ mMax = storage_value;
+ }
+ F64 old_mean = mMean;
+ mMean += ((F64)storage_value - old_mean) / (F64)mNumSamples;
+ mVarianceSum += ((F64)storage_value - old_mean) * ((F64)storage_value - mMean);
+ mLastValue = storage_value;
+ }
+
+ void addSamples(const self_t& other)
+ {
+ if (other.mNumSamples)
+ {
+ mSum += other.mSum;
+ if (other.mMin < mMin)
+ {
+ mMin = other.mMin;
+ }
+ if (other.mMax > mMax)
+ {
+ mMax = other.mMax;
+ }
+ F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples);
+ mNumSamples += other.mNumSamples;
+ mMean = mMean * weight + other.mMean * (1.f - weight);
+
+ // combine variance (and hence standard deviation) of 2 different sized sample groups using
+ // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm
+ F64 n_1 = (F64)mNumSamples,
+ n_2 = (F64)other.mNumSamples;
+ F64 m_1 = mMean,
+ m_2 = other.mMean;
+ F64 sd_1 = getStandardDeviation(),
+ sd_2 = other.getStandardDeviation();
+ if (n_1 == 0)
+ {
+ mVarianceSum = other.mVarianceSum;
+ }
+ else if (n_2 == 0)
+ {
+ // don't touch variance
+ // mVarianceSum = mVarianceSum;
+ }
+ else
+ {
+ mVarianceSum = (F64)mNumSamples
+ * ((((n_1 - 1.f) * sd_1 * sd_1)
+ + ((n_2 - 1.f) * sd_2 * sd_2)
+ + (((n_1 * n_2) / (n_1 + n_2))
+ * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2))))
+ / (n_1 + n_2 - 1.f));
+ }
+ mLastValue = other.mLastValue;
+ }
+ }
+
+ void reset(const self_t* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ mMin = 0;
+ mMax = 0;
+ mMean = 0;
+ mVarianceSum = 0;
+ mLastValue = other ? other->mLastValue : 0;
+ }
+
+ T getSum() const { return (T)mSum; }
+ T getMin() const { return (T)mMin; }
+ T getMax() const { return (T)mMax; }
+ T getLastValue() const { return (T)mLastValue; }
+ F64 getMean() const { return mMean; }
+ F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); }
+ U32 getSampleCount() const { return mNumSamples; }
+
+ private:
+ T mSum,
+ mMin,
+ mMax,
+ mLastValue;
+
+ F64 mMean,
+ mVarianceSum;
+
+ U32 mNumSamples;
+ };
+
+ template<typename T>
+ class CountAccumulator
+ {
+ public:
+ typedef CountAccumulator<T> self_t;
+ typedef T value_t;
+
+ CountAccumulator()
+ : mSum(0),
+ mNumSamples(0)
+ {}
+
+ LL_FORCE_INLINE void add(T value)
+ {
+ mNumSamples++;
+ mSum += value;
+ }
+
+ void addSamples(const CountAccumulator<T>& other)
+ {
+ mSum += other.mSum;
+ mNumSamples += other.mNumSamples;
+ }
+
+ void reset(const self_t* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ }
+
+ T getSum() const { return (T)mSum; }
+
+ U32 getSampleCount() const { return mNumSamples; }
+
+ private:
+ T mSum;
+
+ U32 mNumSamples;
+ };
+
+ class TimeBlockAccumulator
+ {
+ public:
+ typedef LLUnit<LLUnits::Seconds, F64> value_t;
+ typedef TimeBlockAccumulator self_t;
+
+ // fake class that allows us to view call count aspect of timeblock accumulator
+ struct CallCountAspect
+ {
+ typedef U32 value_t;
+ };
+
+ struct SelfTimeAspect
+ {
+ typedef LLUnit<LLUnits::Seconds, F64> value_t;
+ };
+
+ TimeBlockAccumulator();
+ void addSamples(const self_t& other);
+ void reset(const self_t* other);
+
+ //
+ // members
+ //
+ U64 mSelfTimeCounter,
+ mTotalTimeCounter;
+ U32 mCalls;
+ class TimeBlock* mParent; // last acknowledged parent of this time block
+ class TimeBlock* mLastCaller; // used to bootstrap tree construction
+ U16 mActiveCount; // number of timers with this ID active on stack
+ bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
+
+ };
+
+
+ template<>
+ struct MeanValueType<TraceType<TimeBlockAccumulator> >
+ {
+ typedef LLUnit<LLUnits::Seconds, F64> type;
+ };
+
+ template<>
+ class TraceType<TimeBlockAccumulator::CallCountAspect>
+ : public TraceType<TimeBlockAccumulator>
+ {
+ public:
+ typedef F32 mean_t;
+
+ TraceType(const char* name, const char* description = "")
+ : TraceType<TimeBlockAccumulator>(name, description)
+ {}
+ };
+
+ template<>
+ class TraceType<TimeBlockAccumulator::SelfTimeAspect>
+ : public TraceType<TimeBlockAccumulator>
+ {
+ public:
+ typedef F32 mean_t;
+
+ TraceType(const char* name, const char* description = "")
+ : TraceType<TimeBlockAccumulator>(name, description)
+ {}
+ };
+
+ class TimeBlock;
+ class TimeBlockTreeNode
+ {
+ public:
+ TimeBlockTreeNode();
+
+ void setParent(TimeBlock* parent);
+ TimeBlock* getParent() { return mParent; }
+
+ TimeBlock* mBlock;
+ TimeBlock* mParent;
+ std::vector<TimeBlock*> mChildren;
+ bool mNeedsSorting;
+ };
+
+
+ template <typename T = F64>
+ class Measurement
+ : public TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >
+ {
+ public:
+ typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t;
+ typedef TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > trace_t;
+
+ Measurement(const char* name, const char* description = NULL)
+ : trace_t(name, description)
+ {}
+
+ template<typename UNIT_T>
+ void sample(UNIT_T value)
+ {
+ T converted_value(value);
+ trace_t::getPrimaryAccumulator()->sample(LLUnits::rawValue(converted_value));
+ }
+ };
+
+ template <typename T = F64>
+ class Count
+ : public TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >
+ {
+ public:
+ typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t;
+ typedef TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > trace_t;
+
+ Count(const char* name, const char* description = NULL)
+ : trace_t(name)
+ {}
+
+ template<typename UNIT_T>
+ void add(UNIT_T value)
+ {
+ T converted_value(value);
+ 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 DERIVED>
+class MemTrackable
+{
+ template<typename TRACKED, typename TRACKED_IS_TRACKER>
+ struct TrackMemImpl;
+
+ typedef MemTrackable<DERIVED> 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 = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ 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 = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ 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 = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ 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 = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ 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 CLAIM_T>
+ CLAIM_T& memClaim(CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::claim(*this, value);
+ return value;
+ }
+
+ template<typename CLAIM_T>
+ const CLAIM_T& memClaim(const CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::claim(*this, value);
+ return value;
+ }
+
+
+ void memClaim(size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ mMemFootprint += size;
+ if (accumulator)
+ {
+ accumulator->mSize += size;
+ }
+ }
+
+ // remove memory we had claimed from our calculated footprint
+ template<typename CLAIM_T>
+ CLAIM_T& memDisclaim(CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::disclaim(*this, value);
+ return value;
+ }
+
+ template<typename CLAIM_T>
+ const CLAIM_T& memDisclaim(const CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::disclaim(*this, value);
+ return value;
+ }
+
+ void memDisclaim(size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ 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 = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ 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 = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ 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 = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mChildSize += MemFootprint<TRACKED>::measure(tracked);
+ }
+ }
+
+ static void disclaim(mem_trackable_t& tracker, TRACKED& tracked)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mChildSize -= MemFootprint<TRACKED>::measure(tracked);
+ }
+ }
+ };
+};
+
+}
+#endif // LL_LLTRACE_H
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
new file mode 100644
index 0000000000..c110e64380
--- /dev/null
+++ b/indra/llcommon/lltracerecording.cpp
@@ -0,0 +1,636 @@
+/**
+ * @file lltracesampler.cpp
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#include "linden_common.h"
+
+#include "lltrace.h"
+#include "llfasttimer.h"
+#include "lltracerecording.h"
+#include "lltracethreadrecorder.h"
+#include "llthread.h"
+
+namespace LLTrace
+{
+
+///////////////////////////////////////////////////////////////////////
+// Recording
+///////////////////////////////////////////////////////////////////////
+
+Recording::Recording()
+: mElapsedSeconds(0),
+ mCountsFloat(new AccumulatorBuffer<CountAccumulator<F64> >()),
+ mMeasurementsFloat(new AccumulatorBuffer<MeasurementAccumulator<F64> >()),
+ mCounts(new AccumulatorBuffer<CountAccumulator<S64> >()),
+ mMeasurements(new AccumulatorBuffer<MeasurementAccumulator<S64> >()),
+ mStackTimers(new AccumulatorBuffer<TimeBlockAccumulator>()),
+ mMemStats(new AccumulatorBuffer<MemStatAccumulator>())
+{}
+
+Recording::Recording( const Recording& other )
+{
+ llassert(other.mCountsFloat.notNull());
+ mSamplingTimer = other.mSamplingTimer;
+ mElapsedSeconds = other.mElapsedSeconds;
+ mCountsFloat = other.mCountsFloat;
+ mMeasurementsFloat = other.mMeasurementsFloat;
+ mCounts = other.mCounts;
+ mMeasurements = other.mMeasurements;
+ mStackTimers = other.mStackTimers;
+ mMemStats = other.mMemStats;
+
+ LLStopWatchControlsMixin<Recording>::initTo(other.getPlayState());
+}
+
+
+Recording::~Recording()
+{
+ stop();
+ llassert(isStopped());
+}
+
+void Recording::update()
+{
+ if (isStarted())
+ {
+ LLTrace::get_thread_recorder()->update(this);
+ mSamplingTimer.reset();
+ }
+}
+
+void Recording::handleReset()
+{
+ mCountsFloat.write()->reset();
+ mMeasurementsFloat.write()->reset();
+ mCounts.write()->reset();
+ mMeasurements.write()->reset();
+ mStackTimers.write()->reset();
+ mMemStats.write()->reset();
+
+ mElapsedSeconds = 0.0;
+ mSamplingTimer.reset();
+}
+
+void Recording::handleStart()
+{
+ mSamplingTimer.reset();
+ LLTrace::get_thread_recorder()->activate(this);
+}
+
+void Recording::handleStop()
+{
+ mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
+ LLTrace::TimeBlock::processTimes();
+ LLTrace::get_thread_recorder()->deactivate(this);
+}
+
+void Recording::handleSplitTo(Recording& other)
+{
+ stop();
+ other.restart();
+ other.mMeasurementsFloat.write()->reset(mMeasurementsFloat);
+ other.mMeasurements.write()->reset(mMeasurements);
+ //TODO: figure out how to get seamless handoff of timing stats
+}
+
+void Recording::makePrimary()
+{
+ mCountsFloat.write()->makePrimary();
+ mMeasurementsFloat.write()->makePrimary();
+ mCounts.write()->makePrimary();
+ mMeasurements.write()->makePrimary();
+ mStackTimers.write()->makePrimary();
+ mMemStats.write()->makePrimary();
+
+ ThreadRecorder* thread_recorder = get_thread_recorder().get();
+ AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = *mStackTimers.write();
+ // update stacktimer parent pointers
+ for (S32 i = 0, end_i = mStackTimers->size(); i < end_i; i++)
+ {
+ TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i);
+ if (tree_node)
+ {
+ timer_accumulator_buffer[i].mParent = tree_node->mParent;
+ }
+ }
+}
+
+bool Recording::isPrimary() const
+{
+ return mCounts->isPrimary();
+}
+
+void Recording::makeUnique()
+{
+ mCountsFloat.makeUnique();
+ mMeasurementsFloat.makeUnique();
+ mCounts.makeUnique();
+ mMeasurements.makeUnique();
+ mStackTimers.makeUnique();
+ mMemStats.makeUnique();
+}
+
+void Recording::appendRecording( const Recording& other )
+{
+ mCountsFloat.write()->addSamples(*other.mCountsFloat);
+ mMeasurementsFloat.write()->addSamples(*other.mMeasurementsFloat);
+ mCounts.write()->addSamples(*other.mCounts);
+ mMeasurements.write()->addSamples(*other.mMeasurements);
+ mMemStats.write()->addSamples(*other.mMemStats);
+
+ mStackTimers.write()->addSamples(*other.mStackTimers);
+ mElapsedSeconds += other.mElapsedSeconds;
+}
+
+void Recording::mergeRecording( const Recording& other)
+{
+ mCountsFloat.write()->addSamples(*other.mCountsFloat);
+ mMeasurementsFloat.write()->addSamples(*other.mMeasurementsFloat);
+ mCounts.write()->addSamples(*other.mCounts);
+ mMeasurements.write()->addSamples(*other.mMeasurements);
+ mMemStats.write()->addSamples(*other.mMemStats);
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mTotalTimeCounter / (F64)LLTrace::TimeBlock::countsPerSecond();
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / (F64)LLTrace::TimeBlock::countsPerSecond();
+}
+
+
+U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
+{
+ return (*mStackTimers)[stat.getIndex()].mCalls;
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mTotalTimeCounter / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const
+{
+ return (F64)(*mStackTimers)[stat.getIndex()].mSelfTimeCounter / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
+}
+
+F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
+{
+ return (F32)(*mStackTimers)[stat.getIndex()].mCalls / mElapsedSeconds;
+}
+
+LLUnit<LLUnits::Bytes, U32> Recording::getSum(const TraceType<MemStatAccumulator>& stat) const
+{
+ return (*mMemStats)[stat.getIndex()].mAllocatedCount;
+}
+
+LLUnit<LLUnits::Bytes, F32> Recording::getPerSec(const TraceType<MemStatAccumulator>& stat) const
+{
+ return (F32)(*mMemStats)[stat.getIndex()].mAllocatedCount / mElapsedSeconds;
+}
+
+
+F64 Recording::getSum( const TraceType<CountAccumulator<F64> >& stat ) const
+{
+ return (*mCountsFloat)[stat.getIndex()].getSum();
+}
+
+S64 Recording::getSum( const TraceType<CountAccumulator<S64> >& stat ) const
+{
+ return (*mCounts)[stat.getIndex()].getSum();
+}
+
+F64 Recording::getSum( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (F64)(*mMeasurementsFloat)[stat.getIndex()].getSum();
+}
+
+S64 Recording::getSum( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (S64)(*mMeasurements)[stat.getIndex()].getSum();
+}
+
+
+
+F64 Recording::getPerSec( const TraceType<CountAccumulator<F64> >& stat ) const
+{
+ F64 sum = (*mCountsFloat)[stat.getIndex()].getSum();
+ return (sum != 0.0)
+ ? (sum / mElapsedSeconds)
+ : 0.0;
+}
+
+F64 Recording::getPerSec( const TraceType<CountAccumulator<S64> >& stat ) const
+{
+ S64 sum = (*mCounts)[stat.getIndex()].getSum();
+ return (sum != 0)
+ ? ((F64)sum / mElapsedSeconds)
+ : 0.0;
+}
+
+U32 Recording::getSampleCount( const TraceType<CountAccumulator<F64> >& stat ) const
+{
+ return (*mCountsFloat)[stat.getIndex()].getSampleCount();
+}
+
+U32 Recording::getSampleCount( const TraceType<CountAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getSampleCount();
+}
+
+
+F64 Recording::getPerSec( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ F64 sum = (*mMeasurementsFloat)[stat.getIndex()].getSum();
+ return (sum != 0.0)
+ ? (sum / mElapsedSeconds)
+ : 0.0;
+}
+
+F64 Recording::getPerSec( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ S64 sum = (*mMeasurements)[stat.getIndex()].getSum();
+ return (sum != 0)
+ ? ((F64)sum / mElapsedSeconds)
+ : 0.0;
+}
+
+F64 Recording::getMin( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getMin();
+}
+
+S64 Recording::getMin( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getMin();
+}
+
+F64 Recording::getMax( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getMax();
+}
+
+S64 Recording::getMax( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getMax();
+}
+
+F64 Recording::getMean( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getMean();
+}
+
+F64 Recording::getMean( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getMean();
+}
+
+F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getStandardDeviation();
+}
+
+F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getStandardDeviation();
+}
+
+F64 Recording::getLastValue( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getLastValue();
+}
+
+S64 Recording::getLastValue( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getLastValue();
+}
+
+U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<F64> >& stat ) const
+{
+ return (*mMeasurementsFloat)[stat.getIndex()].getSampleCount();
+}
+
+U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<S64> >& stat ) const
+{
+ return (*mMeasurements)[stat.getIndex()].getSampleCount();
+}
+
+
+
+///////////////////////////////////////////////////////////////////////
+// PeriodicRecording
+///////////////////////////////////////////////////////////////////////
+
+PeriodicRecording::PeriodicRecording( S32 num_periods, EStopWatchState state)
+: mNumPeriods(num_periods),
+ mCurPeriod(0),
+ mTotalValid(false),
+ mRecordingPeriods( new Recording[num_periods])
+{
+ llassert(mNumPeriods > 0);
+ initTo(state);
+}
+
+PeriodicRecording::PeriodicRecording(PeriodicRecording& other)
+: mNumPeriods(other.mNumPeriods),
+ mCurPeriod(other.mCurPeriod),
+ mTotalValid(other.mTotalValid),
+ mTotalRecording(other.mTotalRecording)
+{
+ mRecordingPeriods = new Recording[mNumPeriods];
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ mRecordingPeriods[i] = other.mRecordingPeriods[i];
+ }
+}
+
+
+PeriodicRecording::~PeriodicRecording()
+{
+ delete[] mRecordingPeriods;
+}
+
+
+void PeriodicRecording::nextPeriod()
+{
+ EStopWatchState play_state = getPlayState();
+ Recording& old_recording = getCurRecordingPeriod();
+ mCurPeriod = (mCurPeriod + 1) % mNumPeriods;
+ old_recording.splitTo(getCurRecordingPeriod());
+
+ switch(play_state)
+ {
+ case STOPPED:
+ getCurRecordingPeriod().stop();
+ break;
+ case PAUSED:
+ getCurRecordingPeriod().pause();
+ break;
+ case STARTED:
+ break;
+ }
+ // new period, need to recalculate total
+ mTotalValid = false;
+}
+
+Recording& PeriodicRecording::getTotalRecording()
+{
+ if (!mTotalValid)
+ {
+ mTotalRecording.reset();
+ for (S32 i = mCurPeriod + 1; i < mCurPeriod + mNumPeriods; i++)
+ {
+ mTotalRecording.appendRecording(mRecordingPeriods[i % mNumPeriods]);
+ }
+ }
+ mTotalValid = true;
+ return mTotalRecording;
+}
+
+void PeriodicRecording::start()
+{
+ getCurRecordingPeriod().start();
+}
+
+void PeriodicRecording::stop()
+{
+ getCurRecordingPeriod().stop();
+}
+
+void PeriodicRecording::pause()
+{
+ getCurRecordingPeriod().pause();
+}
+
+void PeriodicRecording::resume()
+{
+ getCurRecordingPeriod().resume();
+}
+
+void PeriodicRecording::restart()
+{
+ getCurRecordingPeriod().restart();
+}
+
+void PeriodicRecording::reset()
+{
+ getCurRecordingPeriod().reset();
+}
+
+void PeriodicRecording::splitTo(PeriodicRecording& other)
+{
+ getCurRecordingPeriod().splitTo(other.getCurRecordingPeriod());
+}
+
+void PeriodicRecording::splitFrom(PeriodicRecording& other)
+{
+ getCurRecordingPeriod().splitFrom(other.getCurRecordingPeriod());
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// ExtendableRecording
+///////////////////////////////////////////////////////////////////////
+
+void ExtendableRecording::extend()
+{
+ mAcceptedRecording.appendRecording(mPotentialRecording);
+ mPotentialRecording.reset();
+}
+
+void ExtendableRecording::start()
+{
+ mPotentialRecording.start();
+}
+
+void ExtendableRecording::stop()
+{
+ mPotentialRecording.stop();
+}
+
+void ExtendableRecording::pause()
+{
+ mPotentialRecording.pause();
+}
+
+void ExtendableRecording::resume()
+{
+ mPotentialRecording.resume();
+}
+
+void ExtendableRecording::restart()
+{
+ mAcceptedRecording.reset();
+ mPotentialRecording.restart();
+}
+
+void ExtendableRecording::reset()
+{
+ mAcceptedRecording.reset();
+ mPotentialRecording.reset();
+}
+
+void ExtendableRecording::splitTo(ExtendableRecording& other)
+{
+ mPotentialRecording.splitTo(other.mPotentialRecording);
+}
+
+void ExtendableRecording::splitFrom(ExtendableRecording& other)
+{
+ mPotentialRecording.splitFrom(other.mPotentialRecording);
+}
+
+PeriodicRecording& get_frame_recording()
+{
+ static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(64, PeriodicRecording::STARTED));
+ return *sRecording;
+}
+
+}
+
+void LLStopWatchControlsMixinCommon::start()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ handleReset();
+ handleStart();
+ break;
+ case PAUSED:
+ handleStart();
+ break;
+ case STARTED:
+ handleReset();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::stop()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ handleStop();
+ break;
+ case STARTED:
+ handleStop();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STOPPED;
+}
+
+void LLStopWatchControlsMixinCommon::pause()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ break;
+ case STARTED:
+ handleStop();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = PAUSED;
+}
+
+void LLStopWatchControlsMixinCommon::resume()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ handleStart();
+ break;
+ case PAUSED:
+ handleStart();
+ break;
+ case STARTED:
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::restart()
+{
+ switch (mState)
+ {
+ case STOPPED:
+ handleReset();
+ handleStart();
+ break;
+ case PAUSED:
+ handleReset();
+ handleStart();
+ break;
+ case STARTED:
+ handleReset();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::reset()
+{
+ handleReset();
+}
+
+void LLStopWatchControlsMixinCommon::initTo( EStopWatchState state )
+{
+ switch(state)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ break;
+ case STARTED:
+ handleStart();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+
+ mState = state;
+}
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
new file mode 100644
index 0000000000..aa3200e5ad
--- /dev/null
+++ b/indra/llcommon/lltracerecording.h
@@ -0,0 +1,410 @@
+/**
+ * @file lltracerecording.h
+ * @brief Sampling object for collecting runtime statistics originating from lltrace.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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_LLTRACERECORDING_H
+#define LL_LLTRACERECORDING_H
+
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+
+#include "llpointer.h"
+#include "lltimer.h"
+#include "lltrace.h"
+
+class LLStopWatchControlsMixinCommon
+{
+public:
+ virtual ~LLStopWatchControlsMixinCommon() {}
+
+ enum EStopWatchState
+ {
+ STOPPED,
+ PAUSED,
+ STARTED
+ };
+
+ virtual void start();
+ virtual void stop();
+ virtual void pause();
+ virtual void resume();
+ virtual void restart();
+ virtual void reset();
+
+ bool isStarted() const { return mState == STARTED; }
+ bool isPaused() const { return mState == PAUSED; }
+ bool isStopped() const { return mState == STOPPED; }
+ EStopWatchState getPlayState() const { return mState; }
+
+protected:
+ LLStopWatchControlsMixinCommon()
+ : mState(STOPPED)
+ {}
+
+ // derived classes can call this from their copy constructor in order
+ // to duplicate play state of source
+ void initTo(EStopWatchState state);
+private:
+ // trigger active behavior (without reset)
+ virtual void handleStart(){};
+ // stop active behavior
+ virtual void handleStop(){};
+ // clear accumulated state, can be called while started
+ virtual void handleReset(){};
+
+ EStopWatchState mState;
+};
+
+template<typename DERIVED>
+class LLStopWatchControlsMixin
+: public LLStopWatchControlsMixinCommon
+{
+public:
+ typedef LLStopWatchControlsMixin<DERIVED> self_t;
+ virtual void splitTo(DERIVED& other)
+ {
+ handleSplitTo(other);
+ }
+
+ virtual void splitFrom(DERIVED& other)
+ {
+ static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this));
+ }
+private:
+ // atomically stop this object while starting the other
+ // no data can be missed in between stop and start
+ virtual void handleSplitTo(DERIVED& other) {};
+
+};
+
+namespace LLTrace
+{
+ class Recording : public LLStopWatchControlsMixin<Recording>
+ {
+ public:
+ Recording();
+
+ Recording(const Recording& other);
+ ~Recording();
+
+ void makePrimary();
+ bool isPrimary() const;
+
+ void makeUnique();
+
+ // accumulate data from subsequent, non-overlapping recording
+ void appendRecording(const Recording& other);
+
+ // gather data from recording, ignoring time relationship (for example, pulling data from slave threads)
+ void mergeRecording(const Recording& other);
+
+ void update();
+
+ // Timer accessors
+ LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator>& stat) const;
+ LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const;
+ U32 getSum(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const;
+
+ LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator>& stat) const;
+ LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const;
+ F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const;
+
+ // Memory accessors
+ LLUnit<LLUnits::Bytes, U32> getSum(const TraceType<MemStatAccumulator>& stat) const;
+ LLUnit<LLUnits::Bytes, F32> getPerSec(const TraceType<MemStatAccumulator>& stat) const;
+
+ // Count accessors
+ F64 getSum(const TraceType<CountAccumulator<F64> >& stat) const;
+ S64 getSum(const TraceType<CountAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getSum(const Count<T>& stat) const
+ {
+ return (T)getSum(static_cast<const TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ F64 getPerSec(const TraceType<CountAccumulator<F64> >& stat) const;
+ F64 getPerSec(const TraceType<CountAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getPerSec(const Count<T>& stat) const
+ {
+ return (T)getPerSec(static_cast<const TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ U32 getSampleCount(const TraceType<CountAccumulator<F64> >& stat) const;
+ U32 getSampleCount(const TraceType<CountAccumulator<S64> >& stat) const;
+
+
+ // Measurement accessors
+ F64 getSum(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ S64 getSum(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getSum(const Measurement<T>& stat) const
+ {
+ return (T)getSum(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ F64 getPerSec(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ F64 getPerSec(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getPerSec(const Measurement<T>& stat) const
+ {
+ return (T)getPerSec(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ F64 getMin(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ S64 getMin(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getMin(const Measurement<T>& stat) const
+ {
+ return (T)getMin(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ F64 getMax(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ S64 getMax(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getMax(const Measurement<T>& stat) const
+ {
+ return (T)getMax(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ F64 getMean(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ F64 getMean(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getMean(Measurement<T>& stat) const
+ {
+ return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ F64 getStandardDeviation(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ F64 getStandardDeviation(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getStandardDeviation(const Measurement<T>& stat) const
+ {
+ return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ F64 getLastValue(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ S64 getLastValue(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+ template <typename T>
+ T getLastValue(const Measurement<T>& stat) const
+ {
+ return (T)getLastValue(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
+ }
+
+ U32 getSampleCount(const TraceType<MeasurementAccumulator<F64> >& stat) const;
+ U32 getSampleCount(const TraceType<MeasurementAccumulator<S64> >& stat) const;
+
+ LLUnit<LLUnits::Seconds, F64> getDuration() const { return LLUnit<LLUnits::Seconds, F64>(mElapsedSeconds); }
+
+ private:
+ friend class ThreadRecorder;
+
+ // implementation for LLStopWatchControlsMixin
+ /*virtual*/ void handleStart();
+ /*virtual*/ void handleStop();
+ /*virtual*/ void handleReset();
+ /*virtual*/ void handleSplitTo(Recording& other);
+
+ // returns data for current thread
+ class ThreadRecorder* getThreadRecorder();
+
+ LLCopyOnWritePointer<AccumulatorBuffer<CountAccumulator<F64> > > mCountsFloat;
+ LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<F64> > > mMeasurementsFloat;
+ LLCopyOnWritePointer<AccumulatorBuffer<CountAccumulator<S64> > > mCounts;
+ LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<S64> > > mMeasurements;
+ LLCopyOnWritePointer<AccumulatorBuffer<TimeBlockAccumulator> > mStackTimers;
+ LLCopyOnWritePointer<AccumulatorBuffer<MemStatAccumulator> > mMemStats;
+
+ LLTimer mSamplingTimer;
+ F64 mElapsedSeconds;
+ };
+
+ class LL_COMMON_API PeriodicRecording
+ : public LLStopWatchControlsMixin<PeriodicRecording>
+ {
+ public:
+ PeriodicRecording(S32 num_periods, EStopWatchState state = STOPPED);
+ PeriodicRecording(PeriodicRecording& recording);
+ ~PeriodicRecording();
+
+ void nextPeriod();
+ S32 getNumPeriods() { return mNumPeriods; }
+
+ Recording& getLastRecordingPeriod()
+ {
+ return mRecordingPeriods[(mCurPeriod + mNumPeriods - 1) % mNumPeriods];
+ }
+
+ const Recording& getLastRecordingPeriod() const
+ {
+ return getPrevRecordingPeriod(1);
+ }
+
+ Recording& getCurRecordingPeriod()
+ {
+ return mRecordingPeriods[mCurPeriod];
+ }
+
+ const Recording& getCurRecordingPeriod() const
+ {
+ return mRecordingPeriods[mCurPeriod];
+ }
+
+ Recording& getPrevRecordingPeriod(S32 offset)
+ {
+ offset = llclamp(offset, 0, mNumPeriods - 1);
+ return mRecordingPeriods[(mCurPeriod + mNumPeriods - offset) % mNumPeriods];
+ }
+
+ const Recording& getPrevRecordingPeriod(S32 offset) const
+ {
+ offset = llclamp(offset, 0, mNumPeriods - 1);
+ return mRecordingPeriods[(mCurPeriod + mNumPeriods - offset) % mNumPeriods];
+ }
+
+ Recording snapshotCurRecordingPeriod() const
+ {
+ Recording recording_copy(getCurRecordingPeriod());
+ recording_copy.stop();
+ return recording_copy;
+ }
+
+ Recording& getTotalRecording();
+
+ template <typename T>
+ typename T::value_t getPeriodMin(const TraceType<T>& stat) const
+ {
+ typename T::value_t min_val = (std::numeric_limits<typename T::value_t>::max)();
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ min_val = llmin(min_val, mRecordingPeriods[i].getSum(stat));
+ }
+ return min_val;
+ }
+
+ template <typename T>
+ F64 getPeriodMinPerSec(const TraceType<T>& stat) const
+ {
+ F64 min_val = (std::numeric_limits<F64>::max)();
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ min_val = llmin(min_val, mRecordingPeriods[i].getPerSec(stat));
+ }
+ return min_val;
+ }
+
+ template <typename T>
+ typename T::value_t getPeriodMax(const TraceType<T>& stat) const
+ {
+ typename T::value_t max_val = (std::numeric_limits<typename T::value_t>::min)();
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ max_val = llmax(max_val, mRecordingPeriods[i].getSum(stat));
+ }
+ return max_val;
+ }
+
+ template <typename T>
+ F64 getPeriodMaxPerSec(const TraceType<T>& stat) const
+ {
+ F64 max_val = (std::numeric_limits<F64>::min)();
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ max_val = llmax(max_val, mRecordingPeriods[i].getPerSec(stat));
+ }
+ return max_val;
+ }
+
+ template <typename T>
+ typename TraceType<T>::mean_t getPeriodMean(const TraceType<T>& stat) const
+ {
+ typename TraceType<T>::mean_t mean = 0.0;
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ if (mRecordingPeriods[i].getDuration() > 0.f)
+ {
+ mean += mRecordingPeriods[i].getSum(stat);
+ }
+ }
+ mean /= mNumPeriods;
+ return mean;
+ }
+
+ template <typename T>
+ typename TraceType<T>::mean_t getPeriodMeanPerSec(const TraceType<T>& stat) const
+ {
+ typename TraceType<T>::mean_t mean = 0.0;
+ for (S32 i = 0; i < mNumPeriods; i++)
+ {
+ if (mRecordingPeriods[i].getDuration() > 0.f)
+ {
+ mean += mRecordingPeriods[i].getPerSec(stat);
+ }
+ }
+ mean /= mNumPeriods;
+ return mean;
+ }
+
+ // implementation for LLStopWatchControlsMixin
+ /*virtual*/ void start();
+ /*virtual*/ void stop();
+ /*virtual*/ void pause();
+ /*virtual*/ void resume();
+ /*virtual*/ void restart();
+ /*virtual*/ void reset();
+ /*virtual*/ void splitTo(PeriodicRecording& other);
+ /*virtual*/ void splitFrom(PeriodicRecording& other);
+
+ private:
+ Recording* mRecordingPeriods;
+ Recording mTotalRecording;
+ bool mTotalValid;
+ S32 mNumPeriods,
+ mCurPeriod;
+ };
+
+ PeriodicRecording& get_frame_recording();
+
+ class ExtendableRecording
+ : public LLStopWatchControlsMixin<ExtendableRecording>
+ {
+ void extend();
+
+ // implementation for LLStopWatchControlsMixin
+ /*virtual*/ void start();
+ /*virtual*/ void stop();
+ /*virtual*/ void pause();
+ /*virtual*/ void resume();
+ /*virtual*/ void restart();
+ /*virtual*/ void reset();
+ /*virtual*/ void splitTo(ExtendableRecording& other);
+ /*virtual*/ void splitFrom(ExtendableRecording& other);
+ private:
+ Recording mAcceptedRecording;
+ Recording mPotentialRecording;
+ };
+}
+
+#endif // LL_LLTRACERECORDING_H
diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp
new file mode 100644
index 0000000000..9fb789c62d
--- /dev/null
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -0,0 +1,287 @@
+/**
+ * @file lltracethreadrecorder.cpp
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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$
+ */
+
+#include "linden_common.h"
+
+#include "lltracethreadrecorder.h"
+#include "llfasttimer.h"
+
+namespace LLTrace
+{
+
+
+///////////////////////////////////////////////////////////////////////
+// ThreadRecorder
+///////////////////////////////////////////////////////////////////////
+
+ThreadRecorder::ThreadRecorder()
+{
+ //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies
+ set_thread_recorder(this);
+ TimeBlock& root_time_block = TimeBlock::getRootTimeBlock();
+
+ ThreadTimerStack* timer_stack = ThreadTimerStack::getInstance();
+ timer_stack->mTimeBlock = &root_time_block;
+ timer_stack->mActiveTimer = NULL;
+
+ mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size();
+ mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes];
+
+ mThreadRecording.start();
+
+ // initialize time block parent pointers
+ for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
+ it != end_it;
+ ++it)
+ {
+ TimeBlock& time_block = *it;
+ TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()];
+ tree_node.mBlock = &time_block;
+ tree_node.mParent = &root_time_block;
+
+ it->getPrimaryAccumulator()->mParent = &root_time_block;
+ }
+
+ mRootTimer = new BlockTimer(root_time_block);
+ timer_stack->mActiveTimer = mRootTimer;
+
+ TimeBlock::getRootTimeBlock().getPrimaryAccumulator()->mActiveCount = 1;
+}
+
+ThreadRecorder::~ThreadRecorder()
+{
+ delete mRootTimer;
+
+ while(mActiveRecordings.size())
+ {
+ mActiveRecordings.front().mTargetRecording->stop();
+ }
+ set_thread_recorder(NULL);
+ delete[] mTimeBlockTreeNodes;
+}
+
+TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)
+{
+ if (0 <= index && index < mNumTimeBlockTreeNodes)
+ {
+ return &mTimeBlockTreeNodes[index];
+ }
+ return NULL;
+}
+
+
+void ThreadRecorder::activate( Recording* recording )
+{
+ mActiveRecordings.push_front(ActiveRecording(recording));
+ mActiveRecordings.front().mBaseline.makePrimary();
+}
+
+std::list<ThreadRecorder::ActiveRecording>::iterator ThreadRecorder::update( Recording* recording )
+{
+ std::list<ActiveRecording>::iterator it, end_it;
+ for (it = mActiveRecordings.begin(), end_it = mActiveRecordings.end();
+ it != end_it;
+ ++it)
+ {
+ std::list<ActiveRecording>::iterator next_it = it;
+ ++next_it;
+
+ // if we have another recording further down in the stack...
+ if (next_it != mActiveRecordings.end())
+ {
+ // ...push our gathered data down to it
+ next_it->mBaseline.appendRecording(it->mBaseline);
+ }
+
+ // copy accumulated measurements into result buffer and clear accumulator (mBaseline)
+ it->moveBaselineToTarget();
+
+ if (it->mTargetRecording == recording)
+ {
+ // found the recording, so return it
+ break;
+ }
+ }
+
+ if (it == end_it)
+ {
+ llerrs << "Recording not active on this thread" << llendl;
+ }
+
+ return it;
+}
+
+AccumulatorBuffer<CountAccumulator<F64> > gCountsFloat;
+AccumulatorBuffer<MeasurementAccumulator<F64> > gMeasurementsFloat;
+AccumulatorBuffer<CountAccumulator<S64> > gCounts;
+AccumulatorBuffer<MeasurementAccumulator<S64> > gMeasurements;
+AccumulatorBuffer<TimeBlockAccumulator> gStackTimers;
+AccumulatorBuffer<MemStatAccumulator> gMemStats;
+
+void ThreadRecorder::deactivate( Recording* recording )
+{
+ std::list<ActiveRecording>::iterator it = update(recording);
+ if (it != mActiveRecordings.end())
+ {
+ // and if we've found the recording we wanted to update
+ std::list<ActiveRecording>::iterator next_it = it;
+ ++next_it;
+ if (next_it != mActiveRecordings.end())
+ {
+ next_it->mTargetRecording->makePrimary();
+ }
+
+ mActiveRecordings.erase(it);
+ }
+}
+
+ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target )
+: mTargetRecording(target)
+{
+}
+
+void ThreadRecorder::ActiveRecording::moveBaselineToTarget()
+{
+ mTargetRecording->mMeasurementsFloat.write()->addSamples(*mBaseline.mMeasurementsFloat);
+ mTargetRecording->mCountsFloat.write()->addSamples(*mBaseline.mCountsFloat);
+ mTargetRecording->mMeasurements.write()->addSamples(*mBaseline.mMeasurements);
+ mTargetRecording->mCounts.write()->addSamples(*mBaseline.mCounts);
+ mTargetRecording->mStackTimers.write()->addSamples(*mBaseline.mStackTimers);
+ mBaseline.mMeasurementsFloat.write()->reset();
+ mBaseline.mCountsFloat.write()->reset();
+ mBaseline.mMeasurements.write()->reset();
+ mBaseline.mCounts.write()->reset();
+ mBaseline.mStackTimers.write()->reset();
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// SlaveThreadRecorder
+///////////////////////////////////////////////////////////////////////
+
+SlaveThreadRecorder::SlaveThreadRecorder()
+{
+ getMasterThreadRecorder().addSlaveThread(this);
+}
+
+SlaveThreadRecorder::~SlaveThreadRecorder()
+{
+ getMasterThreadRecorder().removeSlaveThread(this);
+}
+
+void SlaveThreadRecorder::pushToMaster()
+{
+ mThreadRecording.stop();
+ {
+ LLMutexLock(getMasterThreadRecorder().getSlaveListMutex());
+ mSharedData.appendFrom(mThreadRecording);
+ }
+ mThreadRecording.start();
+}
+
+void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ mRecording.appendRecording(source);
+}
+
+void SlaveThreadRecorder::SharedData::appendTo( Recording& sink )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ sink.appendRecording(mRecording);
+}
+
+void SlaveThreadRecorder::SharedData::mergeFrom( const Recording& source )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ mRecording.mergeRecording(source);
+}
+
+void SlaveThreadRecorder::SharedData::mergeTo( Recording& sink )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ sink.mergeRecording(mRecording);
+}
+
+void SlaveThreadRecorder::SharedData::reset()
+{
+ LLMutexLock lock(&mRecordingMutex);
+ mRecording.reset();
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// MasterThreadRecorder
+///////////////////////////////////////////////////////////////////////
+
+LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data");
+void MasterThreadRecorder::pullFromSlaveThreads()
+{
+ LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
+ if (mActiveRecordings.empty()) return;
+
+ LLMutexLock lock(&mSlaveListMutex);
+
+ Recording& target_recording = mActiveRecordings.front().mBaseline;
+ for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
+ it != end_it;
+ ++it)
+ {
+ // ignore block timing info for now
+ (*it)->mSharedData.mergeTo(target_recording);
+ (*it)->mSharedData.reset();
+ }
+}
+
+void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child )
+{
+ LLMutexLock lock(&mSlaveListMutex);
+
+ mSlaveThreadRecorders.push_back(child);
+}
+
+void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child )
+{
+ LLMutexLock lock(&mSlaveListMutex);
+
+ for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
+ it != end_it;
+ ++it)
+ {
+ if ((*it) == child)
+ {
+ mSlaveThreadRecorders.erase(it);
+ break;
+ }
+ }
+}
+
+void MasterThreadRecorder::pushToMaster()
+{}
+
+MasterThreadRecorder::MasterThreadRecorder()
+{}
+
+}
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
new file mode 100644
index 0000000000..337035974c
--- /dev/null
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -0,0 +1,123 @@
+/**
+ * @file lltrace.h
+ * @brief Runtime statistics accumulation.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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_LLTRACETHREADRECORDER_H
+#define LL_LLTRACETHREADRECORDER_H
+
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+
+#include "llmutex.h"
+#include "lltracerecording.h"
+
+namespace LLTrace
+{
+ class LL_COMMON_API ThreadRecorder
+ {
+ protected:
+ struct ActiveRecording;
+ public:
+ ThreadRecorder();
+
+ virtual ~ThreadRecorder();
+
+ void activate(Recording* recording);
+ std::list<struct ActiveRecording>::iterator update(Recording* recording);
+ void deactivate(Recording* recording);
+
+ virtual void pushToMaster() = 0;
+
+ TimeBlockTreeNode* getTimeBlockTreeNode(S32 index);
+
+ protected:
+ struct ActiveRecording
+ {
+ ActiveRecording(Recording* target);
+
+ Recording* mTargetRecording;
+ Recording mBaseline;
+
+ void moveBaselineToTarget();
+ };
+ Recording mThreadRecording;
+ std::list<ActiveRecording> mActiveRecordings;
+
+ class BlockTimer* mRootTimer;
+ TimeBlockTreeNode* mTimeBlockTreeNodes;
+ size_t mNumTimeBlockTreeNodes;
+ };
+
+ class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder
+ {
+ public:
+ MasterThreadRecorder();
+
+ void addSlaveThread(class SlaveThreadRecorder* child);
+ void removeSlaveThread(class SlaveThreadRecorder* child);
+
+ /*virtual */ void pushToMaster();
+
+ // call this periodically to gather stats data from slave threads
+ void pullFromSlaveThreads();
+
+ LLMutex* getSlaveListMutex() { return &mSlaveListMutex; }
+
+ private:
+
+ typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t;
+
+ slave_thread_recorder_list_t mSlaveThreadRecorders;
+ LLMutex mSlaveListMutex;
+ };
+
+ class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder
+ {
+ public:
+ SlaveThreadRecorder();
+ ~SlaveThreadRecorder();
+
+ // call this periodically to gather stats data for master thread to consume
+ /*virtual*/ void pushToMaster();
+
+ MasterThreadRecorder* mMaster;
+
+ class SharedData
+ {
+ public:
+ void appendFrom(const Recording& source);
+ void appendTo(Recording& sink);
+ void mergeFrom(const Recording& source);
+ void mergeTo(Recording& sink);
+ void reset();
+ private:
+ LLMutex mRecordingMutex;
+ Recording mRecording;
+ };
+ SharedData mSharedData;
+ };
+}
+
+#endif // LL_LLTRACETHREADRECORDER_H
diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h
new file mode 100644
index 0000000000..c600883607
--- /dev/null
+++ b/indra/llcommon/llunit.h
@@ -0,0 +1,475 @@
+/**
+ * @file llunit.h
+ * @brief Unit conversion classes
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, 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_LLUNIT_H
+#define LL_LLUNIT_H
+
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+#include "llerrorlegacy.h"
+
+namespace LLUnits
+{
+
+template<typename T>
+struct HighestPrecisionType
+{
+ typedef T type_t;
+};
+
+template<> struct HighestPrecisionType<F32> { typedef F64 type_t; };
+template<> struct HighestPrecisionType<S32> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<U32> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<S16> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<U16> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<S8> { typedef S64 type_t; };
+template<> struct HighestPrecisionType<U8> { typedef S64 type_t; };
+
+template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE>
+struct ConversionFactor
+{
+ static typename HighestPrecisionType<VALUE_TYPE>::type_t get()
+ {
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(DERIVED_UNITS_TAG, false, "Cannot convert between types.");
+ }
+};
+
+template<typename BASE_UNITS_TAG, typename VALUE_TYPE>
+struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE>
+{
+ static typename HighestPrecisionType<VALUE_TYPE>::type_t get()
+ {
+ return 1;
+ }
+};
+
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+struct LLUnit
+{
+ typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> self_t;
+ typedef STORAGE_TYPE storage_t;
+
+ // value initialization
+ LLUnit(storage_t value = storage_t())
+ : mValue(value)
+ {}
+
+ // unit initialization and conversion
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ LLUnit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ : mValue(convert(other))
+ {}
+
+ // value assignment
+ self_t& operator = (storage_t value)
+ {
+ mValue = value;
+ return *this;
+ }
+
+ // unit assignment
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ self_t& operator = (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ {
+ mValue = convert(other);
+ return *this;
+ }
+
+ storage_t value() const
+ {
+ return mValue;
+ }
+
+ template<typename NEW_UNIT_TYPE, typename NEW_STORAGE_TYPE> LLUnit<NEW_UNIT_TYPE, NEW_STORAGE_TYPE> as()
+ {
+ return LLUnit<NEW_UNIT_TYPE, NEW_STORAGE_TYPE>(*this);
+ }
+
+ void operator += (storage_t value)
+ {
+ mValue += value;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator += (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ {
+ mValue += convert(other);
+ }
+
+ void operator -= (storage_t value)
+ {
+ mValue -= value;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator -= (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ {
+ mValue -= convert(other);
+ }
+
+ void operator *= (storage_t multiplicand)
+ {
+ mValue *= multiplicand;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator *= (LLUnit<OTHER_UNIT, OTHER_STORAGE> multiplicand)
+ {
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(OTHER_UNIT, 0, "Multiplication of unit types not supported.");
+ }
+
+ void operator /= (storage_t divisor)
+ {
+ mValue /= divisor;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator /= (LLUnit<OTHER_UNIT, OTHER_STORAGE> divisor)
+ {
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(OTHER_UNIT, 0, "Illegal in-place division of unit types.");
+ }
+
+ template<typename SOURCE_UNITS, typename SOURCE_STORAGE>
+ static storage_t convert(LLUnit<SOURCE_UNITS, SOURCE_STORAGE> v)
+ {
+ return (storage_t)(v.value()
+ * LLUnits::ConversionFactor<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t, SOURCE_STORAGE>::get()
+ * LLUnits::ConversionFactor<typename UNIT_TYPE::base_unit_t, UNIT_TYPE, STORAGE_TYPE>::get());
+ }
+
+protected:
+ storage_t mValue;
+};
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+struct LLUnitImplicit : public LLUnit<UNIT_TYPE, STORAGE_TYPE>
+{
+ typedef LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> self_t;
+ typedef typename LLUnit<UNIT_TYPE, STORAGE_TYPE>::storage_t storage_t;
+ typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> base_t;
+
+ LLUnitImplicit(storage_t value = storage_t())
+ : base_t(value)
+ {}
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ LLUnitImplicit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ : base_t(convert(other))
+ {}
+
+ // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD scalar (F32, S32, etc)
+ // this allows for interoperability with legacy code
+ operator storage_t() const
+ {
+ return base_t::value();
+ }
+};
+
+//
+// operator +
+//
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result += second;
+ return result;
+}
+
+//
+// operator -
+//
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+//
+// operator *
+//
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ return LLUnit<UNIT_TYPE, STORAGE_TYPE>(first * second.value());
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnit<UNIT_TYPE, STORAGE_TYPE>(first.value() * second);
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnit<UNIT_TYPE2, STORAGE_TYPE2>)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(STORAGE_TYPE1, 0, "Multiplication of unit types results in new unit type - not supported.");
+ return LLUnit<UNIT_TYPE1, STORAGE_TYPE1>();
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first * second.value());
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first.value() * second);
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2>)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(STORAGE_TYPE1, 0, "Multiplication of unit types results in new unit type - not supported.");
+ return LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>();
+}
+
+//
+// operator /
+//
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ return SCALAR_TYPE(first / second.value());
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnit<UNIT_TYPE, STORAGE_TYPE>(first.value() / second);
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+STORAGE_TYPE1 operator / (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ return STORAGE_TYPE1(first.value() / second.value());
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first.value() / second);
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+STORAGE_TYPE1 operator / (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ return STORAGE_TYPE1(first.value() / second.value());
+}
+
+#define COMPARISON_OPERATORS(op) \
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \
+bool operator op (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) \
+{ \
+ return first op second.value(); \
+} \
+ \
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \
+bool operator op (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) \
+{ \
+ return first.value() op second; \
+} \
+ \
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \
+bool operator op (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second) \
+{ \
+ return first.value() op first.convert(second); \
+} \
+ \
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \
+ bool operator op (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) \
+{ \
+ return first.value() op first.convert(second); \
+}
+
+COMPARISON_OPERATORS(<)
+COMPARISON_OPERATORS(<=)
+COMPARISON_OPERATORS(>)
+COMPARISON_OPERATORS(>=)
+COMPARISON_OPERATORS(==)
+COMPARISON_OPERATORS(!=)
+
+namespace LLUnits
+{
+template<typename T>
+T rawValue(T val) { return val; }
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+STORAGE_TYPE rawValue(LLUnit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+STORAGE_TYPE rawValue(LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+struct HighestPrecisionType<LLUnit<UNIT_TYPE, STORAGE_TYPE> >
+{
+ typedef typename HighestPrecisionType<STORAGE_TYPE>::type_t type_t;
+};
+
+#define LL_DECLARE_DERIVED_UNIT(conversion_factor, base_unit_name, unit_name) \
+struct unit_name \
+{ \
+ typedef base_unit_name base_unit_t; \
+}; \
+template<typename STORAGE_TYPE> \
+struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE> \
+{ \
+ static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \
+ { \
+ return typename HighestPrecisionType<STORAGE_TYPE>::type_t(conversion_factor); \
+ } \
+}; \
+ \
+template<typename STORAGE_TYPE> \
+struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \
+{ \
+ static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \
+ { \
+ return typename HighestPrecisionType<STORAGE_TYPE>::type_t(1.0 / (conversion_factor)); \
+ } \
+}
+
+struct Bytes { typedef Bytes base_unit_t; };
+LL_DECLARE_DERIVED_UNIT(1024, Bytes, Kilobytes);
+LL_DECLARE_DERIVED_UNIT(1024 * 1024, Bytes, Megabytes);
+LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024, Bytes, Gigabytes);
+LL_DECLARE_DERIVED_UNIT(1.0 / 8.0, Bytes, Bits);
+LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Kilobits);
+LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Megabits);
+LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024 / 8, Bytes, Gigabits);
+
+struct Seconds { typedef Seconds base_unit_t; };
+LL_DECLARE_DERIVED_UNIT(60, Seconds, Minutes);
+LL_DECLARE_DERIVED_UNIT(60 * 60, Seconds, Hours);
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Seconds, Milliseconds);
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000000.0, Seconds, Microseconds);
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000000000.0, Seconds, Nanoseconds);
+
+struct Meters { typedef Meters base_unit_t; };
+LL_DECLARE_DERIVED_UNIT(1000, Meters, Kilometers);
+LL_DECLARE_DERIVED_UNIT(1.0 / 100.0, Meters, Centimeters);
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Meters, Millimeters);
+
+struct Hertz { typedef Hertz base_unit_t; };
+LL_DECLARE_DERIVED_UNIT(1000, Hertz, Kilohertz);
+LL_DECLARE_DERIVED_UNIT(1000 * 1000, Hertz, Megahertz);
+LL_DECLARE_DERIVED_UNIT(1000 * 1000 * 1000, Hertz, Gigahertz);
+} // namespace LLUnits
+
+#endif // LL_LLUNIT_H
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index 0aaa50d231..ba4b670b9a 100644
--- a/indra/llcommon/lluuid.cpp
+++ b/indra/llcommon/lluuid.cpp
@@ -27,9 +27,7 @@
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
#if LL_WINDOWS
-#undef WIN32_LEAN_AND_MEAN
-#include <winsock2.h>
-#include <windows.h>
+#include "llwin32headers.h"
// ugh, this is ugly. We need to straighten out our linking for this library
#pragma comment(lib, "IPHLPAPI.lib")
#include <iphlpapi.h>
diff --git a/indra/llcommon/llwin32headers.h b/indra/llcommon/llwin32headers.h
new file mode 100644
index 0000000000..9c89b6b280
--- /dev/null
+++ b/indra/llcommon/llwin32headers.h
@@ -0,0 +1,36 @@
+/**
+ * @file llwindows.h
+ * @brief sanitized include of windows header files
+ *
+ * $LicenseInfo:firstyear=2001&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_LLWINDOWS_H
+#define LL_LLWINDOWS_H
+
+#ifdef LL_WINDOWS
+#undef WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#endif
diff --git a/indra/llcommon/llwin32headerslean.h b/indra/llcommon/llwin32headerslean.h
new file mode 100644
index 0000000000..d3fb90d4b1
--- /dev/null
+++ b/indra/llcommon/llwin32headerslean.h
@@ -0,0 +1,36 @@
+/**
+ * @file llwindows.h
+ * @brief sanitized include of windows header files
+ *
+ * $LicenseInfo:firstyear=2001&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_LLWINDOWS_H
+#define LL_LLWINDOWS_H
+
+#ifdef LL_WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#endif
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index be46394d6e..09776816a8 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -26,10 +26,11 @@
#ifndef LL_LLWORKERTHREAD_H
#define LL_LLWORKERTHREAD_H
-#include <queue>
-#include <string>
+#include <list>
#include <map>
+#include <queue>
#include <set>
+#include <string>
#include "llqueuedthread.h"
#include "llapr.h"
diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp
new file mode 100644
index 0000000000..2a941e8229
--- /dev/null
+++ b/indra/llcommon/tests/llunits_test.cpp
@@ -0,0 +1,208 @@
+/**
+ * @file llsingleton_test.cpp
+ * @date 2011-08-11
+ * @brief Unit test for the LLSingleton class
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+#include "linden_common.h"
+
+#include "llunit.h"
+#include "../test/lltut.h"
+
+namespace LLUnits
+{
+ // using powers of 2 to allow strict floating point equality
+ struct Quatloos { typedef Quatloos base_unit_t; };
+ LL_DECLARE_DERIVED_UNIT(4, Quatloos, Latinum);
+ LL_DECLARE_DERIVED_UNIT((1.0 / 4.0), Quatloos, Solari);
+}
+
+namespace tut
+{
+ using namespace LLUnits;
+ struct units
+ {
+ };
+
+ typedef test_group<units> units_t;
+ typedef units_t::object units_object_t;
+ tut::units_t tut_singleton("LLUnit");
+
+ // storage type conversions
+ template<> template<>
+ void units_object_t::test<1>()
+ {
+ LLUnit<Quatloos, F32> float_quatloos;
+ ensure(float_quatloos.value() == 0.f);
+
+ LLUnit<Quatloos, S32> int_quatloos;
+ ensure(int_quatloos.value() == 0);
+
+ int_quatloos = 42;
+ ensure(int_quatloos.value() == 42);
+ float_quatloos = int_quatloos;
+ ensure(float_quatloos.value() == 42.f);
+
+ int_quatloos = float_quatloos;
+ ensure(int_quatloos.value() == 42);
+
+ float_quatloos = 42.1f;
+ ensure(float_quatloos.value() == 42.1f);
+ int_quatloos = float_quatloos;
+ ensure(int_quatloos.value() == 42);
+ LLUnit<Quatloos, U32> unsigned_int_quatloos(float_quatloos);
+ ensure(unsigned_int_quatloos.value() == 42);
+ }
+
+ // conversions to/from base unit
+ template<> template<>
+ void units_object_t::test<2>()
+ {
+ LLUnit<Quatloos, F32> quatloos(1.f);
+ ensure(quatloos.value() == 1.f);
+ LLUnit<Latinum, F32> latinum_bars(quatloos);
+ ensure(latinum_bars.value() == 1.f / 4.f);
+
+ latinum_bars = 256;
+ quatloos = latinum_bars;
+ ensure(quatloos.value() == 1024);
+
+ LLUnit<Solari, F32> solari(quatloos);
+ ensure(solari.value() == 4096);
+ }
+
+ // conversions across non-base units
+ template<> template<>
+ void units_object_t::test<3>()
+ {
+ LLUnit<Solari, F32> solari = 4.f;
+ LLUnit<Latinum, F32> latinum_bars = solari;
+ ensure(latinum_bars.value() == 0.25f);
+ }
+
+ // math operations
+ template<> template<>
+ void units_object_t::test<4>()
+ {
+ LLUnit<Quatloos, F32> quatloos = 1.f;
+ quatloos *= 4.f;
+ ensure(quatloos.value() == 4);
+ quatloos = quatloos * 2;
+ ensure(quatloos.value() == 8);
+ quatloos = 2.f * quatloos;
+ ensure(quatloos.value() == 16);
+
+ quatloos += 4.f;
+ ensure(quatloos.value() == 20);
+ quatloos += 4;
+ ensure(quatloos.value() == 24);
+ quatloos = quatloos + 4;
+ ensure(quatloos.value() == 28);
+ quatloos = 4 + quatloos;
+ ensure(quatloos.value() == 32);
+ quatloos += quatloos * 3;
+ ensure(quatloos.value() == 128);
+
+ quatloos -= quatloos / 4 * 3;
+ ensure(quatloos.value() == 32);
+ quatloos = quatloos - 8;
+ ensure(quatloos.value() == 24);
+ quatloos -= 4;
+ ensure(quatloos.value() == 20);
+ quatloos -= 4.f;
+ ensure(quatloos.value() == 16);
+
+ quatloos *= 2.f;
+ ensure(quatloos.value() == 32);
+ quatloos = quatloos * 2.f;
+ ensure(quatloos.value() == 64);
+ quatloos = 0.5f * quatloos;
+ ensure(quatloos.value() == 32);
+
+ quatloos /= 2.f;
+ ensure(quatloos.value() == 16);
+ quatloos = quatloos / 4;
+ ensure(quatloos.value() == 4);
+
+ F32 ratio = quatloos / LLUnit<Quatloos, F32>(4.f);
+ ensure(ratio == 1);
+
+ quatloos += LLUnit<Solari, F32>(4.f);
+ ensure(quatloos.value() == 5);
+ quatloos -= LLUnit<Latinum, F32>(1.f);
+ ensure(quatloos.value() == 1);
+ }
+
+ // implicit units
+ template<> template<>
+ void units_object_t::test<5>()
+ {
+ // 0-initialized
+ LLUnit<Quatloos, F32> quatloos(0);
+ // initialize implicit unit from explicit
+ LLUnitImplicit<Quatloos, F32> quatloos_implicit = quatloos + 1;
+ ensure(quatloos_implicit.value() == 1);
+
+ // assign implicit to explicit, or perform math operations
+ quatloos = quatloos_implicit;
+ ensure(quatloos.value() == 1);
+ quatloos += quatloos_implicit;
+ ensure(quatloos.value() == 2);
+
+ // math operations on implicits
+ quatloos_implicit = 1;
+ ensure(quatloos_implicit == 1);
+
+ quatloos_implicit += 2;
+ ensure(quatloos_implicit == 3);
+
+ quatloos_implicit *= 2;
+ ensure(quatloos_implicit == 6);
+
+ quatloos_implicit -= 1;
+ ensure(quatloos_implicit == 5);
+
+ quatloos_implicit /= 5;
+ ensure(quatloos_implicit == 1);
+
+ quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit;
+ ensure(quatloos_implicit == 5);
+
+ quatloos_implicit = 10 - quatloos_implicit - 1;
+ ensure(quatloos_implicit == 4);
+
+ quatloos_implicit = 2 * quatloos_implicit * 2;
+ ensure(quatloos_implicit == 16);
+
+ F32 one_half = quatloos_implicit / (quatloos_implicit * 2);
+ ensure(one_half == 0.5f);
+
+ // implicit conversion to POD
+ F32 float_val = quatloos_implicit;
+ ensure(float_val == 16);
+
+ S32 int_val = quatloos_implicit;
+ ensure(int_val == 16);
+ }
+}