diff options
| author | Ychebotarev ProductEngine <ychebotarev@productengine.com> | 2010-01-26 12:32:38 +0200 | 
|---|---|---|
| committer | Ychebotarev ProductEngine <ychebotarev@productengine.com> | 2010-01-26 12:32:38 +0200 | 
| commit | a3215a0f09542b513ca06b133631d5b074a308a4 (patch) | |
| tree | f137af067c5f13191485be1c4f6f79e70d9a23c7 | |
| parent | a402b2975fdb88781efa340d186c9ace449f9521 (diff) | |
| parent | b15bebb34853cb839100c48f5b28d52e60660c13 (diff) | |
merge
--HG--
branch : product-engine
22 files changed, 1204 insertions, 338 deletions
| diff --git a/doc/contributions.txt b/doc/contributions.txt index cf10ecccfb..2e4d803252 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -500,6 +500,7 @@ Ringo Tuxing  	CT-231  	CT-321  Robin Cornelius +	SNOW-108  	SNOW-204  	VWR-2488  	VWR-9557 diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index ac7cc2cdac..9ead183a9e 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -50,7 +50,7 @@ set(llcommon_SOURCE_FILES      lleventdispatcher.cpp      lleventfilter.cpp      llevents.cpp -    llfasttimer.cpp +    llfasttimer_class.cpp      llfile.cpp      llfindlocale.cpp      llfixedbuffer.cpp @@ -250,7 +250,7 @@ list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})  if(LLCOMMON_LINK_SHARED)      add_library (llcommon SHARED ${llcommon_SOURCE_FILES}) -	ll_stage_sharedlib(llcommon) +    ll_stage_sharedlib(llcommon)  else(LLCOMMON_LINK_SHARED)      add_library (llcommon ${llcommon_SOURCE_FILES})  endif(LLCOMMON_LINK_SHARED) diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 9920921a58..476d75380f 100644 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -34,7 +34,7 @@  #ifndef LL_LLERRORLEGACY_H  #define LL_LLERRORLEGACY_H - +#include "llpreprocessor.h"  /*  	LEGACY -- DO NOT USE THIS STUFF ANYMORE @@ -107,7 +107,7 @@ const int LL_ERR_PRICE_MISMATCH = -23018;  #define llwarning(msg, num)		llwarns << "Warning # " << num << ": " << msg << llendl; -#define llassert_always(func)	if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; +#define llassert_always(func)	if (LL_UNLIKELY(!(func))) llerrs << "ASSERT (" << #func << ")" << llendl;  #ifdef SHOW_ASSERT  #define llassert(func)			llassert_always(func) diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 8af79c90fd..32f3561616 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,6 +1,6 @@  /**   * @file llfasttimer.h - * @brief Declaration of a fast timer. + * @brief Inline implementations of fast timers.   *   * $LicenseInfo:firstyear=2004&license=viewergpl$   * @@ -33,13 +33,13 @@  #ifndef LL_FASTTIMER_H  #define LL_FASTTIMER_H -#include "llinstancetracker.h" - -#define FAST_TIMER_ON 1 -#define TIME_FAST_TIMERS 0 +// pull in the actual class definition +#include "llfasttimer_class.h"  #if LL_WINDOWS -#define LL_INLINE __forceinline +// +// Windows implementation of CPU clock +//  //  // NOTE: put back in when we aren't using platform sdk anymore @@ -52,21 +52,21 @@  //#undef _interlockedbittestandset  //#undef _interlockedbittestandreset -//inline U32 get_cpu_clock_count_32() +//inline U32 LLFastTimer::getCPUClockCount32()  //{  //	U64 time_stamp = __rdtsc();  //	return (U32)(time_stamp >> 8);  //}  //  //// return full timer value, *not* shifted by 8 bits -//inline U64 get_cpu_clock_count_64() +//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 -inline U32 get_cpu_clock_count_32() +inline U32 LLFastTimer::getCPUClockCount32()  {  	U32 ret_val;  	__asm @@ -82,7 +82,7 @@ inline U32 get_cpu_clock_count_32()  }  // return full timer value, *not* shifted by 8 bits -inline U64 get_cpu_clock_count_64() +inline U64 LLFastTimer::getCPUClockCount64()  {  	U64 ret_val;  	__asm @@ -96,19 +96,48 @@ inline U64 get_cpu_clock_count_64()  	}      return ret_val;  } -#else -#define LL_INLINE  #endif -#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) -inline U32 get_cpu_clock_count_32() + +#if LL_LINUX || LL_SOLARIS +// +// Linux and Solaris implementation of CPU clock - all architectures. +// +// 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. +inline 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, try REALTIME +#endif +		clock_gettime(CLOCK_REALTIME,&tp); + +	return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;         +} + +inline U32 LLFastTimer::getCPUClockCount32() +{ +	return (U32)LLFastTimer::getCPUClockCount64(); +} +#endif // (LL_LINUX || LL_SOLARIS)) + + +#if (LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) +// +// Mac x86 implementation of CPU clock +inline U32 LLFastTimer::getCPUClockCount32()  {  	U64 x;  	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));  	return (U32)x >> 8;  } -inline U32 get_cpu_clock_count_64() +inline U64 LLFastTimer::getCPUClockCount64()  {  	U64 x;  	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); @@ -116,249 +145,22 @@ inline U32 get_cpu_clock_count_64()  }  #endif -#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) + +#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__)))  // -// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock +// Mac PPC (deprecated) implementation of CPU clock  //  // Just use gettimeofday implementation for now -inline U32 get_cpu_clock_count_32() +inline U32 LLFastTimer::getCPUClockCount32()  {  	return (U32)get_clock_count();  } -inline U32 get_cpu_clock_count_64() +inline U64 LLFastTimer::getCPUClockCount64()  {  	return get_clock_count();  }  #endif -class LLMutex; - -#include <queue> -#include "llsd.h" - -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 = 60 }; - -		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_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer) -	:	mFrameState(timer.mFrameState) -	{ -#if TIME_FAST_TIMERS -		U64 timer_start = get_cpu_clock_count_64(); -#endif -#if FAST_TIMER_ON -		LLFastTimer::FrameState* frame_state = mFrameState; -		mStartTime = get_cpu_clock_count_32(); - -		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 = get_cpu_clock_count_64(); -		sTimerCycles += timer_end - timer_start; -#endif -	} - -	LL_INLINE ~LLFastTimer() -	{ -#if TIME_FAST_TIMERS -		U64 timer_start = get_cpu_clock_count_64(); -#endif -#if FAST_TIMER_ON -		LLFastTimer::FrameState* frame_state = mFrameState; -		U32 total_time = get_cpu_clock_count_32() - 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 = get_cpu_clock_count_64(); -		sTimerCycles += timer_end - timer_start; -		sTimerCalls++; -#endif -	} - -public: -	static LLMutex*			sLogLock; -	static std::queue<LLSD> sLogQueue; -	static BOOL				sLog; -	static BOOL				sMetricLog; -	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; - -private: -	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_H diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp new file mode 100644 index 0000000000..abcaee673e --- /dev/null +++ b/indra/llcommon/llfasttimer_class.cpp @@ -0,0 +1,751 @@ +/**  + * @file llfasttimer_class.cpp + * @brief Implementation of the fast timer. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + *  + * Copyright (c) 2004-2007, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS."LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/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 +#elif LL_LINUX || LL_SOLARIS +#include <sys/time.h> +#include <sched.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; +BOOL LLFastTimer::sMetricLog = FALSE; +LLMutex* LLFastTimer::sLogLock = NULL; +std::queue<LLSD> LLFastTimer::sLogQueue; + +#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()  +	{} + +	/*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 (DeclareTimer::instance_iter it = DeclareTimer::beginInstances(); +		it != DeclareTimer::endInstances(); +		++it) +	{ +		// update cached pointer +		it->mFrameState = &it->mTimer.getFrameState(); +	} +} + +//static +#if LL_LINUX || LL_SOLARIS || ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__)) ) +U64 LLFastTimer::countsPerSecond() +{ +	return sClockResolution; +} +#else // windows or x86-mac +U64 LLFastTimer::countsPerSecond() +{ +	static U64 sCPUClockFrequency = U64(CProcessor().GetCPUFrequency(50)); + +	// we drop the low-order byte in out timers, so report a lower frequency +	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) +{ +	if (history_idx < 0) +	{ +		// by default, show average number of calls +		return llformat("%s (%d calls)", getName().c_str(), (S32)getCallAverage()); +	} +	else +	{ +		return llformat("%s (%d calls)", getName().c_str(), (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 = NamedTimer::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 = (timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1); +			timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls; +			timerp->mCallAverage = (timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1); +		} +	} +} + +// static +void LLFastTimer::NamedTimer::resetFrame() +{ +	if (sLog) +	{ //output current frame counts to performance log +		F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency + +		F64 total_time = 0; +		LLSD sd; + +		for (NamedTimer::instance_iter it = NamedTimer::beginInstances(); +					it != NamedTimer::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 (NamedTimer::instance_iter it = NamedTimer::beginInstances(); +		it != NamedTimer::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 (NamedTimer::instance_iter it = NamedTimer::beginInstances(); +		it != NamedTimer::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) +	{ +		sResetHistory = true; +	} +	else if (sResetHistory) +	{ +		sLastFrameIndex = 0; +		sCurFrameIndex = 0; +		sResetHistory = false; +	} +	else // not paused +	{ +		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; +} + + +////////////////////////////////////////////////////////////////////////////// diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h new file mode 100644 index 0000000000..ddb1a74793 --- /dev/null +++ b/indra/llcommon/llfasttimer_class.h @@ -0,0 +1,272 @@ +/** + * @file llfasttimer_class.h + * @brief Declaration of a fast timer. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_FASTTIMER_CLASS_H +#define LL_FASTTIMER_CLASS_H + +#include "llinstancetracker.h" + +#define FAST_TIMER_ON 1 +#define TIME_FAST_TIMERS 0 + +class LLMutex; + +#include <queue> +#include "llsd.h" + +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 = 60 }; + +		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 +	} + +	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 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; + +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/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 5eefa6a16b..1c1503ca7b 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -55,13 +55,28 @@  #define LL_BIG_ENDIAN 1  #endif +  // Per-compiler switches +  #ifdef __GNUC__  #define LL_FORCE_INLINE inline __attribute__((always_inline))  #else  #define LL_FORCE_INLINE __forceinline  #endif +// Mark-up expressions with branch prediction hints.  Do NOT use +// this with reckless abandon - it's an obfuscating micro-optimization +// outside of inner loops or other places where you are OVERWHELMINGLY +// sure which way an expression almost-always evaluates. +#if __GNUC__ >= 3 +# define LL_LIKELY(EXPR) __builtin_expect (!!(EXPR), true) +# define LL_UNLIKELY(EXPR) __builtin_expect (!!(EXPR), false) +#else +# define LL_LIKELY(EXPR) (EXPR) +# define LL_UNLIKELY(EXPR) (EXPR) +#endif + +  // Figure out differences between compilers  #if defined(__GNUC__)  	#define GCC_VERSION (__GNUC__ * 10000 \ diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index cd493481d5..46478ba3c9 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -436,6 +436,8 @@ void LLImageGL::init(BOOL usemipmaps)  	mLastBindTime = 0.f;  	mPickMask = NULL; +	mPickMaskWidth = 0; +	mPickMaskHeight = 0;  	mUseMipMaps = usemipmaps;  	mHasExplicitFormat = FALSE;  	mAutoGenMips = FALSE; @@ -527,7 +529,12 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents)  // 			llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl;  			destroyGLTexture();  		} -		 + +		// pickmask validity depends on old image size, delete it +		delete [] mPickMask; +		mPickMask = NULL; +		mPickMaskWidth = mPickMaskHeight = 0; +  		mWidth = width;  		mHeight = height;  		mComponents = ncomponents; @@ -1675,12 +1682,14 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)  		return ;  	} +	delete [] mPickMask; +	mPickMask = NULL; +	mPickMaskWidth = mPickMaskHeight = 0; +  	if (mFormatType != GL_UNSIGNED_BYTE ||  	    mFormatPrimary != GL_RGBA)  	{  		//cannot generate a pick mask for this texture -		delete [] mPickMask; -		mPickMask = NULL;  		return;  	} @@ -1688,11 +1697,10 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)  	U32 pick_height = height/2;  	U32 size = llmax(pick_width, (U32) 1) * llmax(pick_height, (U32) 1); -  	size = size/8 + 1; - -	delete[] mPickMask;  	mPickMask = new U8[size]; +	mPickMaskWidth = pick_width; +	mPickMaskHeight = pick_height;  	memset(mPickMask, 0, sizeof(U8) * size); @@ -1727,35 +1735,34 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)  	if (mPickMask)  	{ -		S32 width = getWidth()/2; -		S32 height = getHeight()/2; -  		F32 u = tc.mV[0] - floorf(tc.mV[0]);  		F32 v = tc.mV[1] - floorf(tc.mV[1]); -		if (u < 0.f || u > 1.f || -		    v < 0.f || v > 1.f) +		if (LL_UNLIKELY(u < 0.f || u > 1.f || +				v < 0.f || v > 1.f))  		{  			LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL;  			u = v = 0.f;  			llassert(false);  		} + +		llassert(mPickMaskWidth > 0 && mPickMaskHeight > 0); -		S32 x = (S32)(u * width); -		S32 y = (S32)(v * height); +		S32 x = (S32)(u * mPickMaskWidth); +		S32 y = (S32)(v * mPickMaskHeight); -		if (x >= width) +		if (LL_UNLIKELY(x >= mPickMaskWidth))  		{  			LL_WARNS_ONCE("render") << "Ooh, width overrun on pick mask read, that coulda been bad." << LL_ENDL; -			x = llmax(0, width-1); +			x = llmax(0, mPickMaskWidth-1);  		} -		if (y >= height) +		if (LL_UNLIKELY(y >= mPickMaskHeight))  		{  			LL_WARNS_ONCE("render") << "Ooh, height overrun on pick mask read, that woulda been bad." << LL_ENDL; -			y = llmax(0, height-1); +			y = llmax(0, mPickMaskHeight-1);  		} -		S32 idx = y*width+x; +		S32 idx = y*mPickMaskWidth+x;  		S32 offset = idx%8;  		res = mPickMask[idx/8] & (1 << offset) ? TRUE : FALSE; diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index facfb7bd62..f0870c3fc4 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -193,6 +193,8 @@ public:  private:  	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL  	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel +	U16 mPickMaskWidth; +	U16 mPickMaskHeight;  	S8 mUseMipMaps;  	S8 mHasExplicitFormat; // If false (default), GL format is f(mComponents)  	S8 mAutoGenMips; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 72d2e1aba0..093e4f4894 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -298,17 +298,6 @@        <key>Value</key>        <integer>1</integer>      </map> -    <key>AudioStreamingVideo</key> -    <map> -      <key>Comment</key> -      <string>Enable streaming video</string> -      <key>Persist</key> -      <integer>1</integer> -      <key>Type</key> -      <string>Boolean</string> -      <key>Value</key> -      <integer>1</integer> -    </map>    <key>AuditTexture</key>    <map>      <key>Comment</key> diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index cc8f6780e3..887dab66d1 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -192,9 +192,9 @@ NVIDIA GeForce 7100				.*NVIDIA.*GeForce 71.*				0		1  NVIDIA GeForce 7200				.*NVIDIA.*GeForce 72.*				1		1  NVIDIA GeForce 7300				.*NVIDIA.*GeForce 73.*				1		1  NVIDIA GeForce 7500				.*NVIDIA.*GeForce 75.*				1		1 -NVIDIA GeForce 7600				.*NVIDIA.*GeForce 76.*				2		1 -NVIDIA GeForce 7800				.*NVIDIA.*GeForce.*78.*				2		1 -NVIDIA GeForce 7900				.*NVIDIA.*GeForce.*79.*				2		1 +NVIDIA GeForce 7600				.*NVIDIA.*GeForce 76.*				3		1 +NVIDIA GeForce 7800				.*NVIDIA.*GeForce.*78.*				3		1 +NVIDIA GeForce 7900				.*NVIDIA.*GeForce.*79.*				3		1  NVIDIA GeForce 8100				.*NVIDIA.*GeForce 81.*				1		1  NVIDIA GeForce 8200				.*NVIDIA.*GeForce 82.*				1		1  NVIDIA GeForce 8300				.*NVIDIA.*GeForce 83.*				1		1 @@ -207,8 +207,8 @@ NVIDIA GeForce 8800				.*NVIDIA.*GeForce 88.*				3		1  NVIDIA GeForce 9300M			.*NVIDIA.*GeForce 9300M.*			1		1  NVIDIA GeForce 9400M			.*NVIDIA.*GeForce 9400M.*			1		1  NVIDIA GeForce 9500M			.*NVIDIA.*GeForce 9500M.*			2		1 -NVIDIA GeForce 9600M			.*NVIDIA.*GeForce 9600M.*			2		1 -NVIDIA GeForce 9700M			.*NVIDIA.*GeForce 9700M.*			2		1 +NVIDIA GeForce 9600M			.*NVIDIA.*GeForce 9600M.*			3		1 +NVIDIA GeForce 9700M			.*NVIDIA.*GeForce 9700M.*			3		1  NVIDIA GeForce 9300				.*NVIDIA.*GeForce 93.*				1		1  NVIDIA GeForce 9400				.*GeForce 94.*						1		1  NVIDIA GeForce 9500				.*NVIDIA.*GeForce 95.*				2		1 diff --git a/indra/newview/llcallfloater.cpp b/indra/newview/llcallfloater.cpp index d9df537e03..1e713dade8 100644 --- a/indra/newview/llcallfloater.cpp +++ b/indra/newview/llcallfloater.cpp @@ -568,33 +568,46 @@ void LLCallFloater::updateParticipantsVoiceState()  		if (!found)  		{ -			// If an avatarID is not found in a speakers list from VoiceClient and -			// a panel with this ID has a JOINED status this means that this person -			// HAS LEFT the call. -			if ((getState(participant_id) == STATE_JOINED)) -			{ -				setState(item, STATE_LEFT); +			updateNotInVoiceParticipantState(item); +		} +	} +} -				LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(item->getAvatarId()); -				if (speaker.isNull()) -				{ -					continue; -				} +void LLCallFloater::updateNotInVoiceParticipantState(LLAvatarListItem* item) +{ +	LLUUID participant_id = item->getAvatarId(); +	ESpeakerState current_state = getState(participant_id); -				speaker->mHasLeftCurrentCall = TRUE; -			} -			// If an avatarID is not found in a speakers list from VoiceClient and -			// a panel with this ID has a LEFT status this means that this person -			// HAS ENTERED session but it is not in voice chat yet. So, set INVITED status -			else if ((getState(participant_id) != STATE_LEFT)) -			{ -				setState(item, STATE_INVITED); -			} -			else +	switch (current_state) +	{ +	case STATE_JOINED: +		// If an avatarID is not found in a speakers list from VoiceClient and +		// a panel with this ID has a JOINED status this means that this person +		// HAS LEFT the call. +		setState(item, STATE_LEFT); + +		{ +			LLPointer<LLSpeaker> speaker = mSpeakerManager->findSpeaker(participant_id); +			if (speaker.notNull())  			{ -				llwarns << "Unsupported (" << getState(participant_id) << ") state: " << item->getAvatarName()  << llendl; +				speaker->mHasLeftCurrentCall = TRUE;  			}  		} +		break; +	case STATE_INVITED: +	case STATE_LEFT: +		// nothing to do. These states should not be changed. +		break; +	case STATE_UNKNOWN: +		// If an avatarID is not found in a speakers list from VoiceClient and +		// a panel with this ID has an UNKNOWN status this means that this person +		// HAS ENTERED session but it is not in voice chat yet. So, set INVITED status +		setState(item, STATE_INVITED); +		break; +	default: +		// for possible new future states. +		llwarns << "Unsupported (" << getState(participant_id) << ") state for: " << item->getAvatarName()  << llendl; +		break;  	}  } diff --git a/indra/newview/llcallfloater.h b/indra/newview/llcallfloater.h index eded3a426b..766191379b 100644 --- a/indra/newview/llcallfloater.h +++ b/indra/newview/llcallfloater.h @@ -145,6 +145,10 @@ private:  	 */  	void updateParticipantsVoiceState(); +	/** +	 * Updates voice state of participant not in current voice channel depend on its current state. +	 */ +	void updateNotInVoiceParticipantState(LLAvatarListItem* item);  	void setState(LLAvatarListItem* item, ESpeakerState state);  	void setState(const LLUUID& speaker_id, ESpeakerState state)  	{ diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 60c15c253d..e77c93b5f8 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -327,6 +327,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key)  	mCommitCallbackRegistrar.add("Pref.AutoDetectAspect",       boost::bind(&LLFloaterPreference::onCommitAutoDetectAspect, this));	  	mCommitCallbackRegistrar.add("Pref.ParcelMediaAutoPlayEnable",       boost::bind(&LLFloaterPreference::onCommitParcelMediaAutoPlayEnable, this));	  	mCommitCallbackRegistrar.add("Pref.MediaEnabled",           boost::bind(&LLFloaterPreference::onCommitMediaEnabled, this));	 +	mCommitCallbackRegistrar.add("Pref.MusicEnabled",           boost::bind(&LLFloaterPreference::onCommitMusicEnabled, this));	  	mCommitCallbackRegistrar.add("Pref.onSelectAspectRatio",    boost::bind(&LLFloaterPreference::onKeystrokeAspectRatio, this));	  	mCommitCallbackRegistrar.add("Pref.QualityPerformance",     boost::bind(&LLFloaterPreference::onChangeQuality, this, _2));	  	mCommitCallbackRegistrar.add("Pref.applyUIColor",			boost::bind(&LLFloaterPreference::applyUIColor, this ,_1, _2)); @@ -1001,12 +1002,14 @@ void LLFloaterPreference::onCommitMediaEnabled()  {  	LLCheckBoxCtrl *media_enabled_ctrl = getChild<LLCheckBoxCtrl>("media_enabled");  	bool enabled = media_enabled_ctrl->get(); -	gSavedSettings.setBOOL("AudioStreamingVideo", enabled); -	gSavedSettings.setBOOL("AudioStreamingMusic", enabled);  	gSavedSettings.setBOOL("AudioStreamingMedia", enabled); -	media_enabled_ctrl->setTentative(false); -	// Update enabled state of the "autoplay" checkbox -	getChild<LLCheckBoxCtrl>("autoplay_enabled")->setEnabled(enabled); +} + +void LLFloaterPreference::onCommitMusicEnabled() +{ +	LLCheckBoxCtrl *music_enabled_ctrl = getChild<LLCheckBoxCtrl>("music_enabled"); +	bool enabled = music_enabled_ctrl->get(); +	gSavedSettings.setBOOL("AudioStreamingMusic", enabled);  }  void LLFloaterPreference::refresh() @@ -1424,18 +1427,16 @@ BOOL LLPanelPreference::postBuild()  	}  	//////////////////////PanelPrivacy /////////////////// -	if(hasChild("media_enabled")) +	if (hasChild("media_enabled"))  	{ -		bool video_enabled = gSavedSettings.getBOOL("AudioStreamingVideo"); -		bool music_enabled = gSavedSettings.getBOOL("AudioStreamingMusic");  		bool media_enabled = gSavedSettings.getBOOL("AudioStreamingMedia"); -		bool enabled = video_enabled || music_enabled || media_enabled; -		 -		LLCheckBoxCtrl *media_enabled_ctrl = getChild<LLCheckBoxCtrl>("media_enabled");	 -		media_enabled_ctrl->set(enabled); -		media_enabled_ctrl->setTentative(!(video_enabled == music_enabled == media_enabled)); -		getChild<LLCheckBoxCtrl>("autoplay_enabled")->setEnabled(enabled);  		getChild<LLCheckBoxCtrl>("voice_call_friends_only_check")->setCommitCallback(boost::bind(&showFriendsOnlyWarning, _1, _2)); +		getChild<LLCheckBoxCtrl>("media_enabled")->set(media_enabled); +		getChild<LLCheckBoxCtrl>("autoplay_enabled")->setEnabled(media_enabled); +	} +	if (hasChild("music_enabled")) +	{ +		getChild<LLCheckBoxCtrl>("music_enabled")->set(gSavedSettings.getBOOL("AudioStreamingMusic"));  	}  	apply(); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 8b02a4049d..8778d76a5a 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -134,6 +134,7 @@ public:  	void onCommitAutoDetectAspect();  	void onCommitParcelMediaAutoPlayEnable();  	void onCommitMediaEnabled(); +	void onCommitMusicEnabled();  	void applyResolution();  	void applyUIColor(LLUICtrl* ctrl, const LLSD& param);  	void getUIColor(LLUICtrl* ctrl, const LLSD& param);	 diff --git a/indra/newview/llviewerhelp.cpp b/indra/newview/llviewerhelp.cpp index 5af79b4fd3..7c491ad154 100644 --- a/indra/newview/llviewerhelp.cpp +++ b/indra/newview/llviewerhelp.cpp @@ -65,18 +65,16 @@ void LLViewerHelp::showTopic(const std::string &topic)  		help_topic = defaultTopic();  	} -	// f1 help topic means: if user not logged in yet, show the -	// pre-login topic, otherwise show help for the focused item +	// f1 help topic means: if the user is not logged in yet, show +	// the pre-login topic instead of the default fallback topic, +	// otherwise show help for the focused item  	if (help_topic == f1HelpTopic())  	{ -		if (! LLLoginInstance::getInstance()->authSuccess()) +		help_topic = getTopicFromFocus(); +		if (help_topic == defaultTopic() && ! LLLoginInstance::getInstance()->authSuccess())  		{  			help_topic = preLoginTopic();  		} -		else -		{ -			help_topic = getTopicFromFocus(); -		}  	}  	// work out the URL for this topic and display it  diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index d712446d83..98d8780b34 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -940,7 +940,6 @@ bool LLViewerMedia::firstRunCallback(const LLSD& notification, const LLSD& respo  	{  		// user has elected to automatically play media.  		gSavedSettings.setBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING, TRUE); -		gSavedSettings.setBOOL("AudioStreamingVideo", TRUE);  		gSavedSettings.setBOOL("AudioStreamingMusic", TRUE);  		gSavedSettings.setBOOL("AudioStreamingMedia", TRUE); @@ -961,7 +960,6 @@ bool LLViewerMedia::firstRunCallback(const LLSD& notification, const LLSD& respo  	{  		gSavedSettings.setBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING, FALSE);  		gSavedSettings.setBOOL("AudioStreamingMedia", FALSE); -		gSavedSettings.setBOOL("AudioStreamingVideo", FALSE);  		gSavedSettings.setBOOL("AudioStreamingMusic", FALSE);  	}  	return false; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index e87dbe5c07..c4fc2e5cab 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -179,7 +179,7 @@ void LLViewerParcelMedia::play(LLParcel* parcel)  	if (!parcel) return; -	if (!gSavedSettings.getBOOL("AudioStreamingMedia") || !gSavedSettings.getBOOL("AudioStreamingVideo")) +	if (!gSavedSettings.getBOOL("AudioStreamingMedia"))  		return;  	std::string media_url = parcel->getMediaURL(); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3f42cba561..b80dc7d902 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2777,7 +2777,6 @@ void LLViewerMediaTexture::updateClass()  #if 0  	//force to play media.  	gSavedSettings.setBOOL("AudioStreamingMedia", true) ; -	gSavedSettings.setBOOL("AudioStreamingVideo", true) ;  #endif  	for(media_map_t::iterator iter = sMediaMap.begin() ; iter != sMediaMap.end(); ) diff --git a/indra/newview/skins/default/xui/en/floater_aaa.xml b/indra/newview/skins/default/xui/en/floater_aaa.xml index 0b48ba9321..b4d2dabc5c 100644 --- a/indra/newview/skins/default/xui/en/floater_aaa.xml +++ b/indra/newview/skins/default/xui/en/floater_aaa.xml @@ -18,7 +18,8 @@   single_instance="true"    width="320">    <string name="nudge_parabuild">Nudge 1</string> -  <string name="test_the_vlt">This string CHANGE is extracted.</string> +  <string name="test_the_vlt">This string CHANGE2 is extracted.</string> +  <string name="testing_eli">Just a test. change here. more change.</string>    <chat_history     allow_html="true"     bg_readonly_color="ChatHistoryBgColor" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml index a8e24366f2..0aaeb6114e 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml @@ -78,19 +78,19 @@       top_pad="10"       width="350" />  	<check_box -     control_name="MediaEnabled" +     name="media_enabled" +     control_name="AudioStreamingMedia"       height="16"       label="Media Enabled"       layout="topleft"       left="30" -     name="media_enabled"       top_pad="10"       width="350">         <check_box.commit_callback            function="Pref.MediaEnabled" />      </check_box>  	<check_box -	 enabled_control="MediaEnabled" +	 enabled_control="AudioStreamingMedia"       control_name="ParcelMediaAutoPlayEnable"       height="16"       label="Allow Media to auto-play" @@ -102,7 +102,19 @@         <check_box.commit_callback            function="Pref.ParcelMediaAutoPlayEnable" />      </check_box> -   <text +	<check_box +     control_name="AudioStreamingMusic" +     height="16" +     label="Music Enabled" +     layout="topleft" +     left="30" +     name="music_enabled" +     top_pad="10" +     width="350"> +       <check_box.commit_callback +          function="Pref.MusicEnabled" /> +    </check_box> +	<text        type="string"      length="1"      follows="left|top" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 17ababe854..8723e0a832 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -279,7 +279,7 @@        width="480" />      <radio_item        height="20" -      label="Use my browser (IE, Firefox)" +      label="Use my browser (IE, Firefox, Safari)"        layout="topleft"        left_delta="0"        name="external" | 
