diff options
| author | Richard Linden <none@none> | 2013-01-04 16:46:25 -0800 | 
|---|---|---|
| committer | Richard Linden <none@none> | 2013-01-04 16:46:25 -0800 | 
| commit | 0d8f1077a62099915cb532dc354d0e450e3e6a79 (patch) | |
| tree | f76f43d025304bc6aa65d3f91663cac67a6715cc /indra/llcommon | |
| parent | 0d12d171cf20c63a45e7ad0989e65d05aabb86ea (diff) | |
| parent | 7dbb8860373769dfca7d6c6588284866a1bf86a3 (diff) | |
Automated merge with http://bitbucket.org/lindenlab/viewer-development
Diffstat (limited to 'indra/llcommon')
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); +	} +} | 
