diff options
| author | Richard Linden <none@none> | 2013-06-18 23:42:59 -0700 | 
|---|---|---|
| committer | Richard Linden <none@none> | 2013-06-18 23:42:59 -0700 | 
| commit | 8977f43230bda6d7f814e770ba574d016a3875fa (patch) | |
| tree | 16b30705c490a250893699c486e63d4d97c0003f /indra/llcommon | |
| parent | 1bc1d532cff1539bb5366f87b602970f1d2a8929 (diff) | |
| parent | d136c4c29686c565b5a46503aa67a9c958b4145d (diff) | |
Automated merge with bundle:d:\code\viewer-interesting+c:\users\richard\appdata\local\temp\thg.7jrj8n\https__bitbucket.org_lindenlab_viewer-interesting_jch9cd.hg
Diffstat (limited to 'indra/llcommon')
| -rwxr-xr-x | indra/llcommon/llcriticaldamp.cpp | 2 | ||||
| -rwxr-xr-x | indra/llcommon/llcriticaldamp.h | 4 | ||||
| -rwxr-xr-x | indra/llcommon/lldate.cpp | 2 | ||||
| -rwxr-xr-x | indra/llcommon/lldate.h | 2 | ||||
| -rwxr-xr-x | indra/llcommon/llfasttimer.cpp | 95 | ||||
| -rwxr-xr-x | indra/llcommon/llfasttimer.h | 6 | ||||
| -rwxr-xr-x | indra/llcommon/llprocessor.cpp | 2 | ||||
| -rwxr-xr-x | indra/llcommon/llprocessor.h | 2 | ||||
| -rwxr-xr-x | indra/llcommon/lltimer.cpp | 14 | ||||
| -rwxr-xr-x | indra/llcommon/lltimer.h | 16 | ||||
| -rw-r--r-- | indra/llcommon/lltrace.h | 103 | ||||
| -rw-r--r-- | indra/llcommon/lltracerecording.cpp | 238 | ||||
| -rw-r--r-- | indra/llcommon/lltracerecording.h | 58 | ||||
| -rw-r--r-- | indra/llcommon/lltracethreadrecorder.cpp | 1 | ||||
| -rw-r--r-- | indra/llcommon/llunit.h | 442 | ||||
| -rw-r--r-- | indra/llcommon/tests/llunits_test.cpp | 113 | 
16 files changed, 597 insertions, 503 deletions
| diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp index 2f013fe255..575fc4149e 100755 --- a/indra/llcommon/llcriticaldamp.cpp +++ b/indra/llcommon/llcriticaldamp.cpp @@ -81,7 +81,7 @@ void LLSmoothInterpolation::updateInterpolants()  //-----------------------------------------------------------------------------  // getInterpolant()  //----------------------------------------------------------------------------- -F32 LLSmoothInterpolation::getInterpolant(LLUnit<LLUnits::Seconds, F32> time_constant, bool use_cache) +F32 LLSmoothInterpolation::getInterpolant(LLUnit<F32, LLUnits::Seconds> time_constant, bool use_cache)  {  	if (time_constant == 0.f)  	{ diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index ab5d4ba6e2..e174643cd0 100755 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -42,10 +42,10 @@ public:  	static void updateInterpolants();  	// ACCESSORS -	static F32 getInterpolant(LLUnit<LLUnits::Seconds, F32> time_constant, bool use_cache = true); +	static F32 getInterpolant(LLUnit<F32, LLUnits::Seconds> time_constant, bool use_cache = true);  	template<typename T>  -	static T lerp(T a, T b, LLUnit<LLUnits::Seconds, F32> time_constant, bool use_cache = true) +	static T lerp(T a, T b, LLUnit<F32, LLUnits::Seconds> time_constant, bool use_cache = true)  	{  		F32 interpolant = getInterpolant(time_constant, use_cache);  		return ((a * (1.f - interpolant))  diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 2efe39e158..7892269e35 100755 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -55,7 +55,7 @@ LLDate::LLDate(const LLDate& date) :  	mSecondsSinceEpoch(date.mSecondsSinceEpoch)  {} -LLDate::LLDate(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch) : +LLDate::LLDate(LLUnit<F64, LLUnits::Seconds> seconds_since_epoch) :  	mSecondsSinceEpoch(seconds_since_epoch.value())  {} diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index b62a846147..1067ac5280 100755 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -59,7 +59,7 @@ public:  	 *  	 * @param seconds_since_epoch The number of seconds since UTC epoch.  	 */ -	LLDate(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch); +	LLDate(LLUnit<F64, LLUnits::Seconds> seconds_since_epoch);  	/**   	 * @brief Construct a date from a string representation diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index dfc72bd2ce..4da9c3fd6c 100755 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -146,8 +146,8 @@ 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(); - +	static LLUnit<U64, LLUnits::Hertz> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency(); +	return sCPUClockFrequency.value();  #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()) @@ -159,8 +159,8 @@ U64 TimeBlock::countsPerSecond()  		QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);  		firstcall = false;  	} -#endif  	return sCPUClockFrequency.value(); +#endif  }  #endif @@ -178,43 +178,38 @@ TimeBlockTreeNode& TimeBlock::getTreeNode() const  	return *nodep;  } -static LLFastTimer::DeclareTimer FTM_PROCESS_TIMES("Process FastTimer Times"); -// not thread safe, so only call on main thread -//static -void TimeBlock::processTimes() +void TimeBlock::bootstrapTimerTree()  { -	LLFastTimer _(FTM_PROCESS_TIMES); -	get_clock_count(); // good place to calculate clock frequency -	U64 cur_time = getCPUClockCount64(); - -	// set up initial tree  	for (LLInstanceTracker<TimeBlock>::instance_iter begin_it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(), it = begin_it;   		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 +			// 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 +// 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 +void TimeBlock::incrementalUpdateTimerTree() +{  	for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimeBlock());  		it != end_timer_tree_bottom_up();  		++it) @@ -240,27 +235,35 @@ void TimeBlock::processTimes()  				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; +				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 +				// as ancestors may call this timer only on certain paths, so we want to resolve +				// child-most block locations before their parents  				it.skipAncestors();  			}  		}  	} +} + + +void TimeBlock::updateTimes() +{ +	U64 cur_time = getCPUClockCount64();  	// walk up stack of active timers and accumulate current time while leaving timing structures active -	BlockTimerStackRecord* stack_record			= ThreadTimerStack::getInstance(); -	BlockTimer* cur_timer						= stack_record->mActiveTimer; -	TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator(); +	BlockTimerStackRecord* stack_record	= ThreadTimerStack::getInstance(); +	BlockTimer* cur_timer				= stack_record->mActiveTimer; +	TimeBlockAccumulator* accumulator	= stack_record->mTimeBlock->getPrimaryAccumulator();  	while(cur_timer   		&& cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self  	{  		U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; -		accumulator->mTotalTimeCounter += cumulative_time_delta - (accumulator->mTotalTimeCounter - cur_timer->mBlockStartTotalTimeCounter); +		accumulator->mTotalTimeCounter += cumulative_time_delta  +			- (accumulator->mTotalTimeCounter  +			- cur_timer->mBlockStartTotalTimeCounter);  		accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime;  		stack_record->mChildTime = 0; @@ -268,11 +271,28 @@ void TimeBlock::processTimes()  		cur_timer->mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;  		stack_record = &cur_timer->mParentTimerData; -		accumulator = stack_record->mTimeBlock->getPrimaryAccumulator(); -		cur_timer = stack_record->mActiveTimer; +		accumulator  = stack_record->mTimeBlock->getPrimaryAccumulator(); +		cur_timer    = stack_record->mActiveTimer;  		stack_record->mChildTime += cumulative_time_delta;  	} +} + +static LLFastTimer::DeclareTimer FTM_PROCESS_TIMES("Process FastTimer Times"); + +// not thread safe, so only call on main thread +//static +void TimeBlock::processTimes() +{ +	LLFastTimer _(FTM_PROCESS_TIMES); +	get_clock_count(); // good place to calculate clock frequency + +	// set up initial tree +	bootstrapTimerTree(); + +	incrementalUpdateTimerTree(); + +	updateTimes();  	// reset for next frame  	for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), @@ -288,14 +308,13 @@ void TimeBlock::processTimes()  	}  } -  std::vector<TimeBlock*>::iterator TimeBlock::beginChildren() -		{ +{  	return getTreeNode().mChildren.begin();  -		} +}  std::vector<TimeBlock*>::iterator TimeBlock::endChildren() -		{ +{  	return getTreeNode().mChildren.end();  } @@ -318,11 +337,11 @@ void TimeBlock::logStats()  			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; +			LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64()) / (LLUnit<F64, LLUnits::Hertz>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;  		}  		call_count++; -		LLUnit<LLUnits::Seconds, F64> total_time(0); +		LLUnit<F64, LLUnits::Seconds> total_time(0);  		LLSD sd;  		{ @@ -365,11 +384,11 @@ void TimeBlock::dumpCurTimes()  		++it)  	{  		TimeBlock* timerp = (*it); -		LLUnit<LLUnits::Seconds, F64> total_time_ms = last_frame_recording.getSum(*timerp); +		LLUnit<F64, LLUnits::Seconds> total_time = 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; +		if (total_time < LLUnit<F32, LLUnits::Milliseconds>(0.1)) continue;  		std::ostringstream out_str;  		TimeBlock* parent_timerp = timerp; @@ -380,7 +399,7 @@ void TimeBlock::dumpCurTimes()  		}  		out_str << timerp->getName() << " "  -			<< std::setprecision(3) << total_time_ms.as<LLUnits::Milliseconds>().value() << " ms, " +			<< std::setprecision(3) << total_time.getAs<LLUnits::Milliseconds>() << " ms, "  			<< num_calls << " calls";  		llinfos << out_str.str() << llendl; @@ -449,7 +468,7 @@ void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other )  	}  } -LLUnit<LLUnits::Seconds, F64> BlockTimer::getElapsedTime() +LLUnit<F64, LLUnits::Seconds> BlockTimer::getElapsedTime()  {  	U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime; diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 20514d1638..e800befd9f 100755 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -71,7 +71,7 @@ public:  	BlockTimer(TimeBlock& timer);  	~BlockTimer(); -	LLUnit<LLUnits::Seconds, F64> getElapsedTime(); +	LLUnit<F64, LLUnits::Seconds> getElapsedTime();  private: @@ -115,6 +115,7 @@ public:  	static void pushLog(LLSD sd);  	static void setLogLock(LLMutex* mutex);  	static void writeLog(std::ostream& os); +	static void updateTimes();  	// dumps current cumulative frame stats to log  	// call nextFrame() to reset timers @@ -262,6 +263,9 @@ public:  	// can be called multiple times in a frame, at any point  	static void processTimes(); +	static void bootstrapTimerTree(); +	static void incrementalUpdateTimerTree(); +  	// call this once a frame to periodically log timers  	static void logStats(); diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 5ddfa6fcef..b80e813d84 100755 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -875,7 +875,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL)  LLProcessorInfo::~LLProcessorInfo() {} -LLUnitImplicit<LLUnits::Megahertz, F64> LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } +LLUnitImplicit<F64, LLUnits::Megahertz> 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 fbd427f484..7f220467b0 100755 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -37,7 +37,7 @@ public:  	LLProcessorInfo();    	~LLProcessorInfo(); -	LLUnitImplicit<LLUnits::Megahertz, F64> getCPUFrequency() const; +	LLUnitImplicit<F64, LLUnits::Megahertz> getCPUFrequency() const;  	bool hasSSE() const;  	bool hasSSE2() const;  	bool hasAltivec() const; diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 838155d54d..693809b622 100755 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -285,14 +285,14 @@ LLTimer::~LLTimer()  }  // static -LLUnitImplicit<LLUnits::Microseconds, U64> LLTimer::getTotalTime() +LLUnitImplicit<U64, LLUnits::Microseconds> LLTimer::getTotalTime()  {  	// simply call into the implementation function.  	return totalTime();  }	  // static -LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getTotalSeconds() +LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getTotalSeconds()  {  	return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;  } @@ -341,23 +341,23 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount)  } -LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeF64() const +LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getElapsedTimeF64() const  {  	U64 last = mLastClockCount;  	return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;  } -LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeF32() const +LLUnitImplicit<F32, LLUnits::Seconds> LLTimer::getElapsedTimeF32() const  {  	return (F32)getElapsedTimeF64();  } -LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeAndResetF64() +LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getElapsedTimeAndResetF64()  {  	return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;  } -LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeAndResetF32() +LLUnitImplicit<F32, LLUnits::Seconds> LLTimer::getElapsedTimeAndResetF32()  {  	return (F32)getElapsedTimeAndResetF64();  } @@ -370,7 +370,7 @@ void  LLTimer::setTimerExpirySec(F32 expiration)  		+ (U64)((F32)(expiration * gClockFrequency));  } -LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getRemainingTimeF32() const +LLUnitImplicit<F32, LLUnits::Seconds> 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 0ba87d1e15..9e464c4b1a 100755 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -67,16 +67,16 @@ public:  	// Return a high precision number of seconds since the start of  	// this application instance. -	static LLUnitImplicit<LLUnits::Seconds, F64> getElapsedSeconds() +	static LLUnitImplicit<F64, LLUnits::Seconds> getElapsedSeconds()  	{  		return sTimer->getElapsedTimeF64();  	}  	// Return a high precision usec since epoch -	static LLUnitImplicit<LLUnits::Microseconds, U64> getTotalTime(); +	static LLUnitImplicit<U64, LLUnits::Microseconds> getTotalTime();  	// Return a high precision seconds since epoch -	static LLUnitImplicit<LLUnits::Seconds, F64> getTotalSeconds(); +	static LLUnitImplicit<F64, LLUnits::Seconds> getTotalSeconds();  	// MANIPULATORS @@ -87,16 +87,16 @@ public:  	void setTimerExpirySec(F32 expiration);  	BOOL checkExpirationAndReset(F32 expiration);  	BOOL hasExpired() const; -	LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeAndResetF32();	// Returns elapsed time in seconds with reset -	LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeAndResetF64(); +	LLUnitImplicit<F32, LLUnits::Seconds> getElapsedTimeAndResetF32();	// Returns elapsed time in seconds with reset +	LLUnitImplicit<F64, LLUnits::Seconds> getElapsedTimeAndResetF64(); -	LLUnitImplicit<LLUnits::Seconds, F32> getRemainingTimeF32() const; +	LLUnitImplicit<F32, LLUnits::Seconds> getRemainingTimeF32() const;  	static BOOL knownBadTimer();  	// ACCESSORS -	LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeF32() const;			// Returns elapsed time in seconds -	LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeF64() const;			// Returns elapsed time in seconds +	LLUnitImplicit<F32, LLUnits::Seconds> getElapsedTimeF32() const;			// Returns elapsed time in seconds +	LLUnitImplicit<F64, LLUnits::Seconds> getElapsedTimeF64() const;			// Returns elapsed time in seconds  	bool getStarted() const { return mStarted; } diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index cfe1273b4b..6292534a03 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -44,27 +44,37 @@ namespace LLTrace  {  class Recording; -typedef LLUnit<LLUnits::Bytes, F64>			Bytes; -typedef LLUnit<LLUnits::Kibibytes, F64>		Kibibytes; -typedef LLUnit<LLUnits::Mibibytes, F64>		Mibibytes; -typedef LLUnit<LLUnits::Gibibytes, F64>		Gibibytes; -typedef LLUnit<LLUnits::Bits, F64>			Bits; -typedef LLUnit<LLUnits::Kibibits, F64>		Kibibits; -typedef LLUnit<LLUnits::Mibibits, F64>		Mibibits; -typedef LLUnit<LLUnits::Gibibits, F64>		Gibibits; - -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; +typedef LLUnit<F64, LLUnits::Bytes>			Bytes; +typedef LLUnit<F64, LLUnits::Kibibytes>		Kibibytes; +typedef LLUnit<F64, LLUnits::Mibibytes>		Mibibytes; +typedef LLUnit<F64, LLUnits::Gibibytes>		Gibibytes; +typedef LLUnit<F64, LLUnits::Bits>			Bits; +typedef LLUnit<F64, LLUnits::Kibibits>		Kibibits; +typedef LLUnit<F64, LLUnits::Mibibits>		Mibibits; +typedef LLUnit<F64, LLUnits::Gibibits>		Gibibits; + +typedef LLUnit<F64, LLUnits::Seconds>		Seconds; +typedef LLUnit<F64, LLUnits::Milliseconds>	Milliseconds; +typedef LLUnit<F64, LLUnits::Minutes>		Minutes; +typedef LLUnit<F64, LLUnits::Hours>			Hours; +typedef LLUnit<F64, LLUnits::Milliseconds>	Milliseconds; +typedef LLUnit<F64, LLUnits::Microseconds>	Microseconds; +typedef LLUnit<F64, LLUnits::Nanoseconds>	Nanoseconds; + +typedef LLUnit<F64, LLUnits::Meters>		Meters; +typedef LLUnit<F64, LLUnits::Kilometers>	Kilometers; +typedef LLUnit<F64, LLUnits::Centimeters>	Centimeters; +typedef LLUnit<F64, LLUnits::Millimeters>	Millimeters; + + +template<typename T> +T storage_value(T val) { return val; } + +template<typename UNIT_TYPE, typename STORAGE_TYPE>  +STORAGE_TYPE storage_value(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } + +template<typename UNIT_TYPE, typename STORAGE_TYPE>  +STORAGE_TYPE storage_value(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); }  void init();  void cleanup(); @@ -147,12 +157,12 @@ public:  		}  	} -	void flush() +	void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)  	{  		llassert(mStorageSize >= sNextStorageSlot);  		for (size_t i = 0; i < sNextStorageSlot; i++)  		{ -			mStorage[i].flush(); +			mStorage[i].flush(time_stamp);  		}  	} @@ -217,6 +227,11 @@ public:  	size_t size() const  	{ +		return getNumIndices(); +	} + +	static size_t getNumIndices()  +	{  		return sNextStorageSlot;  	} @@ -263,6 +278,7 @@ public:  	}  	size_t getIndex() const { return mAccumulatorIndex; } +	static size_t getNumIndices() { return AccumulatorBuffer<ACCUMULATOR>::getNumIndices(); }  	virtual const char* getUnitLabel() { return ""; } @@ -364,7 +380,7 @@ public:  		mLastValue = other ? other->mLastValue : 0;  	} -	void flush() {} +	void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}  	F64	getSum() const { return mSum; }  	F64	getMin() const { return mMin; } @@ -408,8 +424,8 @@ public:  	void sample(F64 value)  	{ -		LLUnitImplicit<LLUnits::Seconds, F64> time_stamp = LLTimer::getTotalSeconds(); -		LLUnitImplicit<LLUnits::Seconds, F64> delta_time = time_stamp - mLastSampleTimeStamp; +		LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); +		LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;  		mLastSampleTimeStamp = time_stamp;  		if (mHasValue) @@ -496,10 +512,9 @@ public:  		mHasValue = other ? other->mHasValue : false;  	} -	void flush() +	void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)  	{ -		LLUnitImplicit<LLUnits::Seconds, F64> time_stamp = LLTimer::getTotalSeconds(); -		LLUnitImplicit<LLUnits::Seconds, F64> delta_time = time_stamp - mLastSampleTimeStamp; +		LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp;  		if (mHasValue)  		{ @@ -528,7 +543,7 @@ private:  	F64	mMean,  		mVarianceSum; -	LLUnitImplicit<LLUnits::Seconds, F64>	mLastSampleTimeStamp, +	LLUnitImplicit<F64, LLUnits::Seconds>	mLastSampleTimeStamp,  											mTotalSamplingTime;  	U32	mNumSamples; @@ -563,7 +578,7 @@ public:  		mSum = 0;  	} -	void flush() {} +	void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}  	F64	getSum() const { return mSum; } @@ -578,8 +593,8 @@ private:  class TimeBlockAccumulator  {  public: -	typedef LLUnit<LLUnits::Seconds, F64> value_t; -	typedef LLUnit<LLUnits::Seconds, F64> mean_t; +	typedef LLUnit<F64, LLUnits::Seconds> value_t; +	typedef LLUnit<F64, LLUnits::Seconds> mean_t;  	typedef TimeBlockAccumulator self_t;  	// fake classes that allows us to view different facets of underlying statistic @@ -591,14 +606,14 @@ public:  	struct SelfTimeFacet  	{ -		typedef LLUnit<LLUnits::Seconds, F64> value_t; -		typedef LLUnit<LLUnits::Seconds, F64> mean_t; +		typedef LLUnit<F64, LLUnits::Seconds> value_t; +		typedef LLUnit<F64, LLUnits::Seconds> mean_t;  	};  	TimeBlockAccumulator();  	void addSamples(const self_t& other, bool /*append*/);  	void reset(const self_t* other); -	void flush() {} +	void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {}  	//  	// members @@ -672,7 +687,7 @@ template<typename T, typename VALUE_T>  void record(EventStatHandle<T>& measurement, VALUE_T value)  {  	T converted_value(value); -	measurement.getPrimaryAccumulator()->record(LLUnits::rawValue(converted_value)); +	measurement.getPrimaryAccumulator()->record(storage_value(converted_value));  }  template <typename T = F64> @@ -694,7 +709,7 @@ template<typename T, typename VALUE_T>  void sample(SampleStatHandle<T>& measurement, VALUE_T value)  {  	T converted_value(value); -	measurement.getPrimaryAccumulator()->sample(LLUnits::rawValue(converted_value)); +	measurement.getPrimaryAccumulator()->sample(storage_value(converted_value));  }  template <typename T = F64> @@ -716,7 +731,7 @@ template<typename T, typename VALUE_T>  void add(CountStatHandle<T>& count, VALUE_T value)  {  	T converted_value(value); -	count.getPrimaryAccumulator()->add(LLUnits::rawValue(converted_value)); +	count.getPrimaryAccumulator()->add(storage_value(converted_value));  } @@ -739,8 +754,8 @@ struct MemStatAccumulator  	struct ChildMemFacet  	{ -		typedef LLUnit<LLUnits::Bytes, F64> value_t; -		typedef LLUnit<LLUnits::Bytes, F64> mean_t; +		typedef LLUnit<F64, LLUnits::Bytes> value_t; +		typedef LLUnit<F64, LLUnits::Bytes> mean_t;  	};  	MemStatAccumulator() @@ -764,10 +779,10 @@ struct MemStatAccumulator  		mDeallocatedCount = 0;  	} -	void flush()  +	void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp)   	{ -		mSize.flush(); -		mChildSize.flush(); +		mSize.flush(time_stamp); +		mChildSize.flush(time_stamp);  	}  	SampleAccumulator	mSize, diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index d32504b014..33002929ea 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -107,7 +107,9 @@ void RecordingBuffers::reset(RecordingBuffers* other)  void RecordingBuffers::flush()  { -	mSamples.flush(); +	LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); + +	mSamples.flush(time_stamp);  }  /////////////////////////////////////////////////////////////////////// @@ -122,21 +124,26 @@ Recording::Recording()  Recording::Recording( const Recording& other )  { +	*this = other; +} + +Recording& Recording::operator = (const Recording& other) +{  	// this will allow us to seamlessly start without affecting any data we've acquired from other  	setPlayState(PAUSED);  	Recording& mutable_other = const_cast<Recording&>(other); +	mutable_other.update();  	EPlayState other_play_state = other.getPlayState(); -	mutable_other.pause(); -	mBuffers = other.mBuffers; +	mBuffers = mutable_other.mBuffers;  	LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state); -	mutable_other.setPlayState(other_play_state);  	// above call will clear mElapsedSeconds as a side effect, so copy it here  	mElapsedSeconds = other.mElapsedSeconds;  	mSamplingTimer = other.mSamplingTimer; +	return *this;  } @@ -186,240 +193,198 @@ void Recording::handleSplitTo(Recording& other)  void Recording::appendRecording( const Recording& other )  { -	EPlayState play_state = getPlayState(); -	{ -		pause(); -		mBuffers.write()->append(*other.mBuffers); -		mElapsedSeconds += other.mElapsedSeconds; -	} -	setPlayState(play_state); +	update(); +	mBuffers.write()->append(*other.mBuffers); +	mElapsedSeconds += other.mElapsedSeconds;  }  void Recording::mergeRecording( const Recording& other)  { -	EPlayState play_state = getPlayState(); -	{ -		pause(); -		mBuffers.write()->merge(*other.mBuffers); -	} -	setPlayState(play_state); +	update(); +	mBuffers.write()->merge(*other.mBuffers);  } -LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) +LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat)  {  	const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; -	update();  	return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)   				/ (F64)LLTrace::TimeBlock::countsPerSecond();  } -LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat) +LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat)  {  	const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; -	update();  	return (F64)(accumulator.mSelfTimeCounter) / (F64)LLTrace::TimeBlock::countsPerSecond();  }  U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat)  { -	update();  	return mBuffers->mStackTimers[stat.getIndex()].mCalls;  } -LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat) +LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat)  {  	const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; -	update();  	return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)  -				/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds); +				/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value());  } -LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat) +LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat)  {  	const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; -	update();  	return (F64)(accumulator.mSelfTimeCounter)  -			/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds); +			/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value());  }  F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat)  { -	update(); -	return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds; +	return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds.value();  } -LLUnit<LLUnits::Bytes, F64> Recording::getMin(const TraceType<MemStatAccumulator>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mSize.getMin();  } -LLUnit<LLUnits::Bytes, F64> Recording::getMean(const TraceType<MemStatAccumulator>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mSize.getMean();  } -LLUnit<LLUnits::Bytes, F64> Recording::getMax(const TraceType<MemStatAccumulator>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mSize.getMax();  } -LLUnit<LLUnits::Bytes, F64> Recording::getStandardDeviation(const TraceType<MemStatAccumulator>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mSize.getStandardDeviation();  } -LLUnit<LLUnits::Bytes, F64> Recording::getLastValue(const TraceType<MemStatAccumulator>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getLastValue(const TraceType<MemStatAccumulator>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mSize.getLastValue();  } -LLUnit<LLUnits::Bytes, F64> Recording::getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMin();  } -LLUnit<LLUnits::Bytes, F64> Recording::getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMean();  } -LLUnit<LLUnits::Bytes, F64> Recording::getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMax();  } -LLUnit<LLUnits::Bytes, F64> Recording::getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mChildSize.getStandardDeviation();  } -LLUnit<LLUnits::Bytes, F64> Recording::getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +LLUnit<F64, LLUnits::Bytes> Recording::getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mChildSize.getLastValue();  }  U32 Recording::getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount;  }  U32 Recording::getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat)  { -	update();  	return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount;  }  F64 Recording::getSum( const TraceType<CountAccumulator>& stat )  { -	update();  	return mBuffers->mCounts[stat.getIndex()].getSum();  }  F64 Recording::getSum( const TraceType<EventAccumulator>& stat )  { -	update();  	return (F64)mBuffers->mEvents[stat.getIndex()].getSum();  }  F64 Recording::getPerSec( const TraceType<CountAccumulator>& stat )  { -	update();  	F64 sum = mBuffers->mCounts[stat.getIndex()].getSum();  	return  (sum != 0.0)  -		? (sum / mElapsedSeconds) +		? (sum / mElapsedSeconds.value())  		: 0.0;  }  U32 Recording::getSampleCount( const TraceType<CountAccumulator>& stat )  { -	update();  	return mBuffers->mCounts[stat.getIndex()].getSampleCount();  }  F64 Recording::getMin( const TraceType<SampleAccumulator>& stat )  { -	update();  	return mBuffers->mSamples[stat.getIndex()].getMin();  }  F64 Recording::getMax( const TraceType<SampleAccumulator>& stat )  { -	update();  	return mBuffers->mSamples[stat.getIndex()].getMax();  }  F64 Recording::getMean( const TraceType<SampleAccumulator>& stat )  { -	update();  	return mBuffers->mSamples[stat.getIndex()].getMean();  }  F64 Recording::getStandardDeviation( const TraceType<SampleAccumulator>& stat )  { -	update();  	return mBuffers->mSamples[stat.getIndex()].getStandardDeviation();  }  F64 Recording::getLastValue( const TraceType<SampleAccumulator>& stat )  { -	update();  	return mBuffers->mSamples[stat.getIndex()].getLastValue();  }  U32 Recording::getSampleCount( const TraceType<SampleAccumulator>& stat )  { -	update();  	return mBuffers->mSamples[stat.getIndex()].getSampleCount();  }  F64 Recording::getMin( const TraceType<EventAccumulator>& stat )  { -	update();  	return mBuffers->mEvents[stat.getIndex()].getMin();  }  F64 Recording::getMax( const TraceType<EventAccumulator>& stat )  { -	update();  	return mBuffers->mEvents[stat.getIndex()].getMax();  }  F64 Recording::getMean( const TraceType<EventAccumulator>& stat )  { -	update();  	return mBuffers->mEvents[stat.getIndex()].getMean();  }  F64 Recording::getStandardDeviation( const TraceType<EventAccumulator>& stat )  { -	update();  	return mBuffers->mEvents[stat.getIndex()].getStandardDeviation();  }  F64 Recording::getLastValue( const TraceType<EventAccumulator>& stat )  { -	update();  	return mBuffers->mEvents[stat.getIndex()].getLastValue();  }  U32 Recording::getSampleCount( const TraceType<EventAccumulator>& stat )  { -	update();  	return mBuffers->mEvents[stat.getIndex()].getSampleCount();  } @@ -430,6 +395,7 @@ U32 Recording::getSampleCount( const TraceType<EventAccumulator>& stat )  PeriodicRecording::PeriodicRecording( U32 num_periods, EPlayState state)   :	mAutoResize(num_periods == 0),  	mCurPeriod(0), +	mNumPeriods(0),  	mRecordingPeriods(num_periods ? num_periods : 1)  {  	setPlayState(state); @@ -443,9 +409,16 @@ void PeriodicRecording::nextPeriod()  	}  	Recording& old_recording = getCurRecording(); -  	mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size();  	old_recording.splitTo(getCurRecording()); + +	mNumPeriods = llmin(mRecordingPeriods.size(), mNumPeriods + 1); +} + +void PeriodicRecording::appendRecording(Recording& recording) +{ +	getCurRecording().appendRecording(recording); +	nextPeriod();  } @@ -453,77 +426,71 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )  {  	if (other.mRecordingPeriods.empty()) return; -	EPlayState play_state = getPlayState(); -	pause(); - -	EPlayState other_play_state = other.getPlayState(); -	other.pause(); - -	U32 other_recording_count = other.mRecordingPeriods.size(); - -	Recording& other_oldest_recording = other.mRecordingPeriods[(other.mCurPeriod + 1) % other.mRecordingPeriods.size()]; +	getCurRecording().update(); +	other.getCurRecording().update(); -	// if I have a recording of any length, then close it off and start a fresh one -	if (getCurRecording().getDuration().value()) +	if (mAutoResize)  	{ -		nextPeriod(); -	} -	getCurRecording().appendRecording(other_oldest_recording); +		S32 other_index = (other.mCurPeriod + 1) % other.mRecordingPeriods.size(); +		S32 end_index = (other.mCurPeriod) % other.mRecordingPeriods.size();  -	if (other_recording_count > 1) -	{ -		if (mAutoResize) +		do  		{ -			for (S32 other_index = (other.mCurPeriod + 2) % other_recording_count, -				end_index = (other.mCurPeriod + 1) % other_recording_count;  -				other_index != end_index;  -				other_index = (other_index + 1) % other_recording_count) +			if (other.mRecordingPeriods[other_index].getDuration().value())  			{ -				llassert(other.mRecordingPeriods[other_index].getDuration() != 0.f  -							&& (mRecordingPeriods.empty()  -								|| other.mRecordingPeriods[other_index].getDuration() != mRecordingPeriods.back().getDuration()));  				mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]);  			} - -			mCurPeriod = mRecordingPeriods.size() - 1; +			other_index = (other_index + 1) % other.mRecordingPeriods.size();  		} -		else +		while(other_index != end_index); + +		mCurPeriod = mRecordingPeriods.size() - 1; +		mNumPeriods = mRecordingPeriods.size(); +	} +	else +	{ +		//FIXME: get proper number of recordings from other...might not have used all its slots +		size_t num_to_copy = llmin(	mRecordingPeriods.size(), other.getNumRecordedPeriods()); +		std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin()  +													+ (	(other.mCurPeriod + 1									// oldest period +															+ (other.mRecordingPeriods.size() - num_to_copy))	// minus room for copy +														% other.mRecordingPeriods.size()); +		std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + mCurPeriod; + +		for(size_t i = 0; i < num_to_copy; i++)  		{ -			size_t num_to_copy = llmin(	mRecordingPeriods.size(), other.mRecordingPeriods.size() - 1); -			std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin()  -														+ (	(other.mCurPeriod + 1									// oldest period -																+ (other.mRecordingPeriods.size() - num_to_copy))	// minus room for copy -															% other.mRecordingPeriods.size()); -			std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + ((mCurPeriod + 1) % mRecordingPeriods.size()); - -			for(S32 i = 0; i < num_to_copy; i++) -			{ -				*dest_it = *src_it; +			*dest_it = *src_it; -				if (++src_it == other.mRecordingPeriods.end()) -				{ -					src_it = other.mRecordingPeriods.begin(); -				} +			if (++src_it == other.mRecordingPeriods.end()) +			{ +				src_it = other.mRecordingPeriods.begin(); +			} -				if (++dest_it == mRecordingPeriods.end()) -				{ -					dest_it = mRecordingPeriods.begin(); -				} +			if (++dest_it == mRecordingPeriods.end()) +			{ +				dest_it = mRecordingPeriods.begin();  			} -		 -			mCurPeriod = (mCurPeriod + num_to_copy) % mRecordingPeriods.size();  		} +		 +		// want argument to % to be positive, otherwise result could be negative and thus out of bounds +		llassert(num_to_copy >= 1); +		// advance to last recording period copied, so we can check if the last period had actually carried any data, in which case we'll advance below +		// using nextPeriod() which retains continuity (mLastValue, etc) +		mCurPeriod = (mCurPeriod + num_to_copy - 1) % mRecordingPeriods.size(); +		mNumPeriods = llmin(mRecordingPeriods.size(), mNumPeriods + num_to_copy);  	} -	nextPeriod(); - -	setPlayState(play_state); -	other.setPlayState(other_play_state); +	if (getCurRecording().getDuration().value()) +	{ +		//call this to chain last period copied to new active period +		nextPeriod(); +	} +	getCurRecording().setPlayState(getPlayState());  } -LLUnit<LLUnits::Seconds, F64> PeriodicRecording::getDuration() const +LLUnit<F64, LLUnits::Seconds> PeriodicRecording::getDuration() const  { -	LLUnit<LLUnits::Seconds, F64> duration; +	LLUnit<F64, LLUnits::Seconds> duration;  	size_t num_periods = mRecordingPeriods.size();  	for (size_t i = 1; i <= num_periods; i++)  	{ @@ -615,7 +582,7 @@ void PeriodicRecording::handleSplitTo(PeriodicRecording& other)  F64 PeriodicRecording::getPeriodMean( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )  {  	size_t total_periods = mRecordingPeriods.size(); -	num_periods = llmin(num_periods, total_periods); +	num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  	F64 mean = 0;  	if (num_periods <= 0) { return mean; } @@ -643,7 +610,7 @@ F64 PeriodicRecording::getPeriodMean( const TraceType<EventAccumulator>& stat, s  F64 PeriodicRecording::getPeriodMin( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )  {  	size_t total_periods = mRecordingPeriods.size(); -	num_periods = llmin(num_periods, total_periods); +	num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  	F64 min_val = std::numeric_limits<F64>::max();  	for (S32 i = 1; i <= num_periods; i++) @@ -657,7 +624,7 @@ F64 PeriodicRecording::getPeriodMin( const TraceType<EventAccumulator>& stat, si  F64 PeriodicRecording::getPeriodMax( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )  {  	size_t total_periods = mRecordingPeriods.size(); -	num_periods = llmin(num_periods, total_periods); +	num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  	F64 max_val = std::numeric_limits<F64>::min();  	for (S32 i = 1; i <= num_periods; i++) @@ -671,7 +638,7 @@ F64 PeriodicRecording::getPeriodMax( const TraceType<EventAccumulator>& stat, si  F64 PeriodicRecording::getPeriodMin( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )  {  	size_t total_periods = mRecordingPeriods.size(); -	num_periods = llmin(num_periods, total_periods); +	num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  	F64 min_val = std::numeric_limits<F64>::max();  	for (S32 i = 1; i <= num_periods; i++) @@ -685,7 +652,7 @@ F64 PeriodicRecording::getPeriodMin( const TraceType<SampleAccumulator>& stat, s  F64 PeriodicRecording::getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/)  {  	size_t total_periods = mRecordingPeriods.size(); -	num_periods = llmin(num_periods, total_periods); +	num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  	F64 max_val = std::numeric_limits<F64>::min();  	for (S32 i = 1; i <= num_periods; i++) @@ -700,9 +667,9 @@ F64 PeriodicRecording::getPeriodMax(const TraceType<SampleAccumulator>& stat, si  F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )  {  	size_t total_periods = mRecordingPeriods.size(); -	num_periods = llmin(num_periods, total_periods); +	num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); -	LLUnit<LLUnits::Seconds, F64> total_duration = 0.f; +	LLUnit<F64, LLUnits::Seconds> total_duration = 0.f;  	F64 mean = 0;  	if (num_periods <= 0) { return mean; } @@ -712,7 +679,7 @@ F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat,  		S32 index = (mCurPeriod + total_periods - i) % total_periods;  		if (mRecordingPeriods[index].getDuration() > 0.f)  		{ -			LLUnit<LLUnits::Seconds, F64> recording_duration = mRecordingPeriods[index].getDuration(); +			LLUnit<F64, LLUnits::Seconds> recording_duration = mRecordingPeriods[index].getDuration();  			mean += mRecordingPeriods[index].getMean(stat) * recording_duration.value();  			total_duration += recording_duration;  		} @@ -734,13 +701,11 @@ F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat,  void ExtendableRecording::extend()  {  	// stop recording to get latest data -	mPotentialRecording.stop(); +	mPotentialRecording.update();  	// push the data back to accepted recording  	mAcceptedRecording.appendRecording(mPotentialRecording);  	// flush data, so we can start from scratch  	mPotentialRecording.reset(); -	// go back to play state we were in initially -	mPotentialRecording.setPlayState(getPlayState());  }  void ExtendableRecording::handleStart() @@ -777,15 +742,10 @@ ExtendablePeriodicRecording::ExtendablePeriodicRecording()  void ExtendablePeriodicRecording::extend()  { -	llassert(mPotentialRecording.getPlayState() == getPlayState()); -	// stop recording to get latest data -	mPotentialRecording.pause();  	// push the data back to accepted recording  	mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);  	// flush data, so we can start from scratch  	mPotentialRecording.reset(); -	// go back to play state we were in initially -	mPotentialRecording.setPlayState(getPlayState());  } diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index 4651bfcb61..b839e85de0 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -135,6 +135,8 @@ namespace LLTrace  		Recording(const Recording& other);  		~Recording(); +		Recording& operator = (const Recording& other); +  		// accumulate data from subsequent, non-overlapping recording  		void appendRecording(const Recording& other); @@ -148,26 +150,26 @@ namespace LLTrace  		void makeUnique() { mBuffers.makeUnique(); }  		// Timer accessors -		LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator>& stat); -		LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat); +		LLUnit<F64, LLUnits::Seconds> getSum(const TraceType<TimeBlockAccumulator>& stat); +		LLUnit<F64, LLUnits::Seconds> getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat);  		U32 getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat); -		LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator>& stat); -		LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat); +		LLUnit<F64, LLUnits::Seconds> getPerSec(const TraceType<TimeBlockAccumulator>& stat); +		LLUnit<F64, LLUnits::Seconds> getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat);  		F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat);  		// Memory accessors -		LLUnit<LLUnits::Bytes, F64> getMin(const TraceType<MemStatAccumulator>& stat); -		LLUnit<LLUnits::Bytes, F64> getMean(const TraceType<MemStatAccumulator>& stat); -		LLUnit<LLUnits::Bytes, F64> getMax(const TraceType<MemStatAccumulator>& stat); -		LLUnit<LLUnits::Bytes, F64> getStandardDeviation(const TraceType<MemStatAccumulator>& stat); -		LLUnit<LLUnits::Bytes, F64> getLastValue(const TraceType<MemStatAccumulator>& stat); - -		LLUnit<LLUnits::Bytes, F64> getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); -		LLUnit<LLUnits::Bytes, F64> getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); -		LLUnit<LLUnits::Bytes, F64> getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); -		LLUnit<LLUnits::Bytes, F64> getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); -		LLUnit<LLUnits::Bytes, F64> getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); +		LLUnit<F64, LLUnits::Bytes> getMin(const TraceType<MemStatAccumulator>& stat); +		LLUnit<F64, LLUnits::Bytes> getMean(const TraceType<MemStatAccumulator>& stat); +		LLUnit<F64, LLUnits::Bytes> getMax(const TraceType<MemStatAccumulator>& stat); +		LLUnit<F64, LLUnits::Bytes> getStandardDeviation(const TraceType<MemStatAccumulator>& stat); +		LLUnit<F64, LLUnits::Bytes> getLastValue(const TraceType<MemStatAccumulator>& stat); + +		LLUnit<F64, LLUnits::Bytes> getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); +		LLUnit<F64, LLUnits::Bytes> getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); +		LLUnit<F64, LLUnits::Bytes> getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); +		LLUnit<F64, LLUnits::Bytes> getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); +		LLUnit<F64, LLUnits::Bytes> getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);  		U32 getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat);  		U32 getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat); @@ -273,7 +275,7 @@ namespace LLTrace  		U32 getSampleCount(const TraceType<EventAccumulator>& stat); -		LLUnit<LLUnits::Seconds, F64> getDuration() const { return LLUnit<LLUnits::Seconds, F64>(mElapsedSeconds); } +		LLUnit<F64, LLUnits::Seconds> getDuration() const { return mElapsedSeconds; }  	protected:  		friend class ThreadRecorder; @@ -288,7 +290,7 @@ namespace LLTrace  		class ThreadRecorder* getThreadRecorder();   		LLTimer				mSamplingTimer; -		F64					mElapsedSeconds; +		LLUnit<F64, LLUnits::Seconds>			mElapsedSeconds;  		LLCopyOnWritePointer<RecordingBuffers>	mBuffers;  	}; @@ -299,11 +301,12 @@ namespace LLTrace  		PeriodicRecording(U32 num_periods, EPlayState state = STOPPED);  		void nextPeriod(); -		U32 getNumPeriods() { return mRecordingPeriods.size(); } +		size_t getNumRecordedPeriods() { return mNumPeriods; } -		LLUnit<LLUnits::Seconds, F64> getDuration() const; +		LLUnit<F64, LLUnits::Seconds> getDuration() const;  		void appendPeriodicRecording(PeriodicRecording& other); +		void appendRecording(Recording& recording);  		Recording& getLastRecording();  		const Recording& getLastRecording() const;  		Recording& getCurRecording(); @@ -317,7 +320,7 @@ namespace LLTrace  		typename T::value_t getPeriodMin(const TraceType<T>& stat, size_t num_periods = U32_MAX)  		{  			size_t total_periods = mRecordingPeriods.size(); -			num_periods = llmin(num_periods, total_periods); +			num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  			typename T::value_t min_val = std::numeric_limits<typename T::value_t>::max();  			for (S32 i = 1; i <= num_periods; i++) @@ -346,7 +349,7 @@ namespace LLTrace  		F64 getPeriodMinPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)  		{  			size_t total_periods = mRecordingPeriods.size(); -			num_periods = llmin(num_periods, total_periods); +			num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  			F64 min_val = std::numeric_limits<F64>::max();  			for (S32 i = 1; i <= num_periods; i++) @@ -362,7 +365,7 @@ namespace LLTrace  		typename T::value_t getPeriodMax(const TraceType<T>& stat, size_t num_periods = U32_MAX)  		{  			size_t total_periods = mRecordingPeriods.size(); -			num_periods = llmin(num_periods, total_periods); +			num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  			typename T::value_t max_val = std::numeric_limits<typename T::value_t>::min();  			for (S32 i = 1; i <= num_periods; i++) @@ -391,7 +394,7 @@ namespace LLTrace  		F64 getPeriodMaxPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)  		{  			size_t total_periods = mRecordingPeriods.size(); -			num_periods = llmin(num_periods, total_periods); +			num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  			F64 max_val = std::numeric_limits<F64>::min();  			for (S32 i = 1; i <= num_periods; i++) @@ -407,7 +410,7 @@ namespace LLTrace  		typename T::mean_t getPeriodMean(const TraceType<T >& stat, size_t num_periods = U32_MAX)  		{  			size_t total_periods = mRecordingPeriods.size(); -			num_periods = llmin(num_periods, total_periods); +			num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  			typename T::mean_t mean = 0;  			if (num_periods <= 0) { return mean; } @@ -442,7 +445,7 @@ namespace LLTrace  		typename T::mean_t getPeriodMeanPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)  		{  			size_t total_periods = mRecordingPeriods.size(); -			num_periods = llmin(num_periods, total_periods); +			num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);  			typename T::mean_t mean = 0;  			if (num_periods <= 0) { return mean; } @@ -468,8 +471,9 @@ namespace LLTrace  	private:  		std::vector<Recording>	mRecordingPeriods; -		const bool	mAutoResize; -		S32			mCurPeriod; +		const bool				mAutoResize; +		size_t					mCurPeriod; +		size_t					mNumPeriods;  	};  	PeriodicRecording& get_frame_recording(); diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index c1a0700eff..54006f4e5b 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -111,6 +111,7 @@ ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringU  	if (mActiveRecordings.empty()) return mActiveRecordings.rend();  	mActiveRecordings.back()->mPartialRecording.flush(); +	TimeBlock::updateTimes();  	active_recording_list_t::reverse_iterator it, end_it;  	for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h index f48cbe0e11..5229fe69d7 100644 --- a/indra/llcommon/llunit.h +++ b/indra/llcommon/llunit.h @@ -30,36 +30,12 @@  #include "stdtypes.h"  #include "llpreprocessor.h"  #include "llerrorlegacy.h" +#include <boost/type_traits/is_same.hpp> -namespace LLUnits -{ - -template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE> -struct ConversionFactor -{ -	static F64 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."); -        return 0; -	} -}; - -template<typename BASE_UNITS_TAG, typename VALUE_TYPE> -struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE> -{ -	static F64 get()  -	{  -		return 1;  -	} -}; - -} - -template<typename UNIT_TYPE, typename STORAGE_TYPE> +template<typename STORAGE_TYPE, typename UNIT_TYPE>  struct LLUnit  { -	typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> self_t; +	typedef LLUnit<STORAGE_TYPE, UNIT_TYPE> self_t;  	typedef STORAGE_TYPE storage_t;  	// value initialization @@ -68,11 +44,16 @@ struct LLUnit  	{}  	// unit initialization and conversion -	template<typename OTHER_UNIT, typename OTHER_STORAGE> -	LLUnit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other) -	:	mValue(convert(other)) +	template<typename OTHER_STORAGE, typename OTHER_UNIT> +	LLUnit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other) +	:	mValue(convert(other).mValue)  	{} +	bool operator == (const self_t& other) +	{ +		return mValue = other.mValue; +	} +  	// value assignment  	self_t& operator = (storage_t value)  	{ @@ -81,10 +62,10 @@ struct LLUnit  	}  	// unit assignment -	template<typename OTHER_UNIT, typename OTHER_STORAGE> -	self_t& operator = (LLUnit<OTHER_UNIT, OTHER_STORAGE> other) +	template<typename OTHER_STORAGE, typename OTHER_UNIT> +	self_t& operator = (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)  	{ -		mValue = convert(other); +		mValue = convert(other).mValue;  		return *this;  	} @@ -93,21 +74,27 @@ struct LLUnit  		return mValue;  	} -	template<typename NEW_UNIT_TYPE> LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE> as() +	template<typename NEW_UNIT_TYPE>  +	STORAGE_TYPE getAs()  	{ -		return LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE>(*this); +		return LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(*this).value();  	} +	template<typename NEW_UNIT_TYPE>  +	STORAGE_TYPE setAs(STORAGE_TYPE val) +	{ +		*this = LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(val); +	}  	void operator += (storage_t value)  	{  		mValue += value;  	} -	template<typename OTHER_UNIT, typename OTHER_STORAGE> -	void operator += (LLUnit<OTHER_UNIT, OTHER_STORAGE> other) +	template<typename OTHER_STORAGE, typename OTHER_UNIT> +	void operator += (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)  	{ -		mValue += convert(other); +		mValue += convert(other).mValue;  	}  	void operator -= (storage_t value) @@ -115,10 +102,10 @@ struct LLUnit  		mValue -= value;  	} -	template<typename OTHER_UNIT, typename OTHER_STORAGE> -	void operator -= (LLUnit<OTHER_UNIT, OTHER_STORAGE> other) +	template<typename OTHER_STORAGE, typename OTHER_UNIT> +	void operator -= (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)  	{ -		mValue -= convert(other); +		mValue -= convert(other).mValue;  	}  	void operator *= (storage_t multiplicand) @@ -127,7 +114,7 @@ struct LLUnit  	}  	template<typename OTHER_UNIT, typename OTHER_STORAGE> -	void operator *= (LLUnit<OTHER_UNIT, OTHER_STORAGE> multiplicand) +	void operator *= (LLUnit<OTHER_STORAGE, OTHER_UNIT> multiplicand)  	{  		// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template  		llstatic_assert_template(OTHER_UNIT, false, "Multiplication of unit types not supported."); @@ -139,37 +126,37 @@ struct LLUnit  	}  	template<typename OTHER_UNIT, typename OTHER_STORAGE> -	void operator /= (LLUnit<OTHER_UNIT, OTHER_STORAGE> divisor) +	void operator /= (LLUnit<OTHER_STORAGE, OTHER_UNIT> divisor)  	{  		// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template  		llstatic_assert_template(OTHER_UNIT, false, "Illegal in-place division of unit types.");  	} -	template<typename SOURCE_UNITS, typename SOURCE_STORAGE> -	static storage_t convert(LLUnit<SOURCE_UNITS, SOURCE_STORAGE> v)  +	template<typename SOURCE_STORAGE, typename SOURCE_UNITS> +	static self_t convert(LLUnit<SOURCE_STORAGE, SOURCE_UNITS> 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());  +		self_t result; +		ll_convert_units(v, result); +		return result;  	}  protected:  	storage_t mValue;  }; -template<typename UNIT_TYPE, typename STORAGE_TYPE> -struct LLUnitImplicit : public LLUnit<UNIT_TYPE, STORAGE_TYPE> +template<typename STORAGE_TYPE, typename UNIT_TYPE> +struct LLUnitImplicit : public LLUnit<STORAGE_TYPE, UNIT_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; +	typedef LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> self_t; +	typedef typename LLUnit<STORAGE_TYPE, UNIT_TYPE>::storage_t storage_t; +	typedef LLUnit<STORAGE_TYPE, UNIT_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) +	template<typename OTHER_STORAGE, typename OTHER_UNIT> +	LLUnitImplicit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other)  	:	base_t(convert(other))  	{} @@ -181,53 +168,86 @@ struct LLUnitImplicit : public LLUnit<UNIT_TYPE, STORAGE_TYPE>  	}  }; + +template<typename S1, typename T1, typename S2, typename T2> +LL_FORCE_INLINE void ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out, ...) +{ +	static_assert(boost::is_same<T1, T2>::value  +					|| !boost::is_same<T1, typename T1::base_unit_t>::value  +					|| !boost::is_same<T2, typename T2::base_unit_t>::value,  +				"invalid conversion"); + +	if (boost::is_same<T1, typename T1::base_unit_t>::value) +	{ +		if (boost::is_same<T2, typename T2::base_unit_t>::value) +		{ +			// T1 and T2 fully reduced and equal...just copy +			out = (S2)in.value(); +		} +		else +		{ +			// reduce T2 +			LLUnit<S2, typename T2::base_unit_t> new_out; +			ll_convert_units(in, new_out); +			ll_convert_units(new_out, out); +		} +	} +	else +	{ +		// reduce T1 +		LLUnit<S1, typename T1::base_unit_t> new_in; +		ll_convert_units(in, new_in); +		ll_convert_units(new_in, out); +	} +} +  //  // 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) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)  { -	LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first); +	LLUnit<STORAGE_TYPE1, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); +	LLUnit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second)  { -	LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); +	LLUnit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)  { -	LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first); +	LLUnitImplicit<STORAGE_TYPE1, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator + (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first); +	LLUnitImplicit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second)  { -	LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first); +	LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> result(first);  	result += second;  	return result;  } @@ -235,50 +255,50 @@ LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1,  //  // 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) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator - (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)  { -	LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first); +	LLUnit<STORAGE_TYPE1, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); +	LLUnit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second)  { -	LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first); +	LLUnit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second)  { -	LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first); +	LLUnitImplicit<STORAGE_TYPE1, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator - (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first); +	LLUnitImplicit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator - (SCALAR_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second)  { -	LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first); +	LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> result(first);  	result -= second;  	return result;  } @@ -286,102 +306,100 @@ LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnitImp  //  // 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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator * (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second)  { -	return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first * second.value())); +	return LLUnit<STORAGE_TYPE, 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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator * (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() * second)); +	return LLUnit<STORAGE_TYPE, 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>) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnit<STORAGE_TYPE2, UNIT_TYPE2>)  {  	// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template  	llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported."); -	return LLUnit<UNIT_TYPE1, STORAGE_TYPE1>(); +	return LLUnit<STORAGE_TYPE1, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator * (SCALAR_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second)  { -	return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first * second.value()); +	return LLUnitImplicit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator * (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first.value() * second); +	return LLUnitImplicit<STORAGE_TYPE, UNIT_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>) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2>)  {  	// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template  	llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported."); -	return LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>(); +	return LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>();  }  //  // operator /  // -template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> -SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator / (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second)); +	return LLUnit<STORAGE_TYPE, 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) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +STORAGE_TYPE1 operator / (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_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()); +	return STORAGE_TYPE1(first.value() / first.convert(second));  } -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) +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator / (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)  { -	return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second)); +	return LLUnitImplicit<STORAGE_TYPE, 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) +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +STORAGE_TYPE1 operator / (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_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()); +	return STORAGE_TYPE1(first.value() / first.convert(second));  }  #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)                                         \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>                                            \ +bool operator op (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_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)                                         \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>                                            \ +bool operator op (LLUnit<STORAGE_TYPE, UNIT_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) \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>                   \ +bool operator op (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_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)             \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>                   \ +	bool operator op (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)             \  {                                                                                                                    \  	return first.value() op first.convert(second);                                                                   \  } @@ -401,80 +419,142 @@ struct LLGetUnitLabel  };  template<typename T, typename STORAGE_T> -struct LLGetUnitLabel<LLUnit<T, STORAGE_T> > +struct LLGetUnitLabel<LLUnit<STORAGE_T, T> >  {  	static const char* getUnitLabel() { return T::getUnitLabel(); }  }; -// -// Unit declarations -// -namespace LLUnits +template<typename VALUE_TYPE> +struct LLUnitLinearOps  { -template<typename T> -T rawValue(T val) { return val; } +	typedef LLUnitLinearOps<VALUE_TYPE> self_t; +	LLUnitLinearOps(VALUE_TYPE val) : mValue (val) {} -template<typename UNIT_TYPE, typename STORAGE_TYPE>  -STORAGE_TYPE rawValue(LLUnit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); } +	operator VALUE_TYPE() const { return mValue; } +	VALUE_TYPE mValue; -template<typename UNIT_TYPE, typename STORAGE_TYPE>  -STORAGE_TYPE rawValue(LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); } +	template<typename T> +	self_t operator * (T other) +	{ +		return mValue * other; +	} + +	template<typename T> +	self_t operator / (T other) +	{ +		return mValue / other; +	} + +	template<typename T> +	self_t operator + (T other) +	{ +		return mValue + other; +	} + +	template<typename T> +	self_t operator - (T other) +	{ +		return mValue - other; +	} +}; -#define LL_DECLARE_DERIVED_UNIT(conversion_factor, base_unit_name, unit_name, unit_label)		\ +template<typename VALUE_TYPE> +struct LLUnitInverseLinearOps +{ +	typedef LLUnitInverseLinearOps<VALUE_TYPE> self_t; + +	LLUnitInverseLinearOps(VALUE_TYPE val) : mValue (val) {} +	operator VALUE_TYPE() const { return mValue; } +	VALUE_TYPE mValue; + +	template<typename T> +	self_t operator * (T other) +	{ +		return mValue / other; +	} + +	template<typename T> +	self_t operator / (T other) +	{ +		return mValue * other; +	} + +	template<typename T> +	self_t operator + (T other) +	{ +		return mValue - other; +	} + +	template<typename T> +	self_t operator - (T other) +	{ +		return mValue + other; +	} +}; + +#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ +struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }} + +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation)	\  struct unit_name                                                                                \  {                                                                                               \  	typedef base_unit_name base_unit_t;                                                         \  	static const char* getUnitLabel() { return unit_label; }									\  };                                                                                              \ -template<typename STORAGE_TYPE>                                                                 \ -struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE>                                \ -{                                                                                               \ -	static F64 get()                                                                            \ -	{                                                                                           \ -		return (F64)conversion_factor;                                                          \ -	}                                                                                           \ -};                                                                                              \  	                                                                                            \ -template<typename STORAGE_TYPE>                                                                 \ -struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE>						        \ +template<typename S1, typename S2>                                                              \ +void ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out)                \  {                                                                                               \ -	static F64 get()                                                                            \ -	{                                                                                           \ -		return (F64)(1.0 / (conversion_factor));                                                \ -	}                                                                                           \ -} +	out = (S2)(LLUnitLinearOps<S1>(in.value()) conversion_operation).mValue;                    \ +}                                                                                               \ +                                                                                                \ +template<typename S1, typename S2>                                                              \ +void ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out)                \ +{                                                                                               \ +	out = (S2)(LLUnitInverseLinearOps<S1>(in.value()) conversion_operation).mValue;             \ +}                                                                                                -#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ -struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }} +// +// Unit declarations +// +namespace LLUnits +{  LL_DECLARE_BASE_UNIT(Bytes, "B"); -LL_DECLARE_DERIVED_UNIT(1024, Bytes, Kibibytes, "KiB"); -LL_DECLARE_DERIVED_UNIT(1024 * 1024, Bytes, Mibibytes, "MiB"); -LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024, Bytes, Gibibytes, "GiB"); -LL_DECLARE_DERIVED_UNIT(1.0 / 8.0, Bytes, Bits, "b"); -LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Kibibits, "Kib"); -LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Mibibits, "Mib"); -LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024 / 8, Bytes, Gibibits, "Gib"); +LL_DECLARE_DERIVED_UNIT(Kilobytes, "KB", Bytes, * 1000); +LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Kilobytes, * 1000); +LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Megabytes, * 1000); +LL_DECLARE_DERIVED_UNIT(Kibibytes, "KiB", Bytes, * 1024); +LL_DECLARE_DERIVED_UNIT(Mibibytes, "MiB", Kibibytes, * 1024); +LL_DECLARE_DERIVED_UNIT(Gibibytes, "GiB", Mibibytes, * 1024); + +LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, / 8); +LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bytes, * 1000 / 8); +LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, * 1000 / 8); +LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, * 1000 / 8); +LL_DECLARE_DERIVED_UNIT(Kibibits, "Kib", Bytes, * 1024 / 8); +LL_DECLARE_DERIVED_UNIT(Mibibits, "Mib", Kibibits, * 1024 / 8); +LL_DECLARE_DERIVED_UNIT(Gibibits, "Gib", Mibibits, * 1024 / 8);  LL_DECLARE_BASE_UNIT(Seconds, "s"); -LL_DECLARE_DERIVED_UNIT(60, Seconds, Minutes, "min"); -LL_DECLARE_DERIVED_UNIT(60 * 60, Seconds, Hours, "h"); -LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Seconds, Milliseconds, "ms"); -LL_DECLARE_DERIVED_UNIT(1.0 / 1000000.0, Seconds, Microseconds, "\x09\x3cs"); -LL_DECLARE_DERIVED_UNIT(1.0 / 1000000000.0, Seconds, Nanoseconds, "ns"); +LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, * 60); +LL_DECLARE_DERIVED_UNIT(Hours, "h", Seconds, * 60 * 60); +LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, / 1000); +LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, / 1000); +LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, / 1000);  LL_DECLARE_BASE_UNIT(Meters, "m"); -LL_DECLARE_DERIVED_UNIT(1000, Meters, Kilometers, "km"); -LL_DECLARE_DERIVED_UNIT(1.0 / 100.0, Meters, Centimeters, "cm"); -LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Meters, Millimeters, "mm"); +LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, * 1000); +LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, / 100); +LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, / 1000);  LL_DECLARE_BASE_UNIT(Hertz, "Hz"); -LL_DECLARE_DERIVED_UNIT(1000, Hertz, Kilohertz, "KHz"); -LL_DECLARE_DERIVED_UNIT(1000 * 1000, Hertz, Megahertz, "MHz"); -LL_DECLARE_DERIVED_UNIT(1000 * 1000 * 1000, Hertz, Gigahertz, "GHz"); +LL_DECLARE_DERIVED_UNIT(Kilohertz, "KHz", Hertz, * 1000); +LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Kilohertz, * 1000); +LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Megahertz, * 1000);  LL_DECLARE_BASE_UNIT(Radians, "rad"); -LL_DECLARE_DERIVED_UNIT(0.01745329251994, Radians, Degrees, "deg"); +LL_DECLARE_DERIVED_UNIT(Degrees, "deg", Radians, * 0.01745329251994);  } // namespace LLUnits diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp index 33e30f9688..a5df51f6de 100644 --- a/indra/llcommon/tests/llunits_test.cpp +++ b/indra/llcommon/tests/llunits_test.cpp @@ -34,8 +34,8 @@ namespace LLUnits  {  	// using powers of 2 to allow strict floating point equality  	LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); -	LL_DECLARE_DERIVED_UNIT(4, Quatloos, Latinum, "Lat"); -	LL_DECLARE_DERIVED_UNIT((1.0 / 4.0), Quatloos, Solari, "Sol"); +	LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, * 4); +	LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, / 16);  }  namespace tut @@ -53,105 +53,110 @@ namespace tut  	template<> template<>  	void units_object_t::test<1>()  	{ -		LLUnit<Quatloos, F32> float_quatloos; -		ensure(float_quatloos.value() == 0.f); +		LLUnit<F32, Quatloos> float_quatloos; +		ensure(float_quatloos == 0.f); -		LLUnit<Quatloos, S32> int_quatloos; -		ensure(int_quatloos.value() == 0); +		LLUnit<F32, Quatloos> float_initialize_quatloos(1); +		ensure(float_initialize_quatloos == 1.f); + +		LLUnit<S32, Quatloos> int_quatloos; +		ensure(int_quatloos == 0);  		int_quatloos = 42; -		ensure(int_quatloos.value() == 42); +		ensure(int_quatloos == 42);  		float_quatloos = int_quatloos; -		ensure(float_quatloos.value() == 42.f); +		ensure(float_quatloos == 42.f);  		int_quatloos = float_quatloos; -		ensure(int_quatloos.value() == 42); +		ensure(int_quatloos == 42);  		float_quatloos = 42.1f; -		ensure(float_quatloos.value() == 42.1f); +		ensure(float_quatloos == 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); +		ensure(int_quatloos == 42); +		LLUnit<U32, Quatloos> unsigned_int_quatloos(float_quatloos); +		ensure(unsigned_int_quatloos == 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); +		LLUnit<F32, Quatloos> quatloos(1.f); +		ensure(quatloos == 1.f); +		LLUnit<F32, Latinum> latinum_bars(quatloos); +		ensure(latinum_bars == 1.f / 4.f);  		latinum_bars = 256;  		quatloos = latinum_bars; -		ensure(quatloos.value() == 1024); +		ensure(quatloos == 1024); -		LLUnit<Solari, F32> solari(quatloos); -		ensure(solari.value() == 4096); +		LLUnit<F32, Solari> solari(quatloos); +		ensure(solari == 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); +		LLUnit<F32, Solari> solari = 4.f; +		LLUnit<F32, Latinum> latinum_bars = solari; +		ensure(latinum_bars == 0.25f);  	}  	// math operations  	template<> template<>  	void units_object_t::test<4>()  	{ -		LLUnit<Quatloos, F32> quatloos = 1.f; +		LLUnit<F32, Quatloos> quatloos = 1.f;  		quatloos *= 4.f; -		ensure(quatloos.value() == 4); +		ensure(quatloos == 4);  		quatloos = quatloos * 2; -		ensure(quatloos.value() == 8); +		ensure(quatloos == 8);  		quatloos = 2.f * quatloos; -		ensure(quatloos.value() == 16); +		ensure(quatloos == 16);  		quatloos += 4.f; -		ensure(quatloos.value() == 20); +		ensure(quatloos == 20);  		quatloos += 4; -		ensure(quatloos.value() == 24); +		ensure(quatloos == 24);  		quatloos = quatloos + 4; -		ensure(quatloos.value() == 28); +		ensure(quatloos == 28);  		quatloos = 4 + quatloos; -		ensure(quatloos.value() == 32); +		ensure(quatloos == 32);  		quatloos += quatloos * 3; -		ensure(quatloos.value() == 128); +		ensure(quatloos == 128);  		quatloos -= quatloos / 4 * 3; -		ensure(quatloos.value() == 32); +		ensure(quatloos == 32);  		quatloos = quatloos - 8; -		ensure(quatloos.value() == 24); +		ensure(quatloos == 24);  		quatloos -= 4; -		ensure(quatloos.value() == 20); +		ensure(quatloos == 20);  		quatloos -= 4.f; -		ensure(quatloos.value() == 16); +		ensure(quatloos == 16);  		quatloos *= 2.f; -		ensure(quatloos.value() == 32); +		ensure(quatloos == 32);  		quatloos = quatloos * 2.f; -		ensure(quatloos.value() == 64); +		ensure(quatloos == 64);  		quatloos = 0.5f * quatloos; -		ensure(quatloos.value() == 32); +		ensure(quatloos == 32);  		quatloos /= 2.f; -		ensure(quatloos.value() == 16); +		ensure(quatloos == 16);  		quatloos = quatloos / 4; -		ensure(quatloos.value() == 4); +		ensure(quatloos == 4); -		F32 ratio = quatloos / LLUnit<Quatloos, F32>(4.f); +		F32 ratio = quatloos / LLUnit<F32, Quatloos>(4.f); +		ensure(ratio == 1); +		ratio = quatloos / LLUnit<F32, Solari>(16.f);  		ensure(ratio == 1); -		quatloos += LLUnit<Solari, F32>(4.f); -		ensure(quatloos.value() == 5); -		quatloos -= LLUnit<Latinum, F32>(1.f); -		ensure(quatloos.value() == 1); +		quatloos += LLUnit<F32, Solari>(4.f); +		ensure(quatloos == 5); +		quatloos -= LLUnit<F32, Latinum>(1.f); +		ensure(quatloos == 1);  	}  	// implicit units @@ -159,16 +164,16 @@ namespace tut  	void units_object_t::test<5>()  	{  		// 0-initialized -		LLUnit<Quatloos, F32> quatloos(0); +		LLUnit<F32, Quatloos> quatloos(0);  		// initialize implicit unit from explicit -		LLUnitImplicit<Quatloos, F32> quatloos_implicit = quatloos + 1; -		ensure(quatloos_implicit.value() == 1); +		LLUnitImplicit<F32, Quatloos> quatloos_implicit = quatloos + 1; +		ensure(quatloos_implicit == 1);  		// assign implicit to explicit, or perform math operations  		quatloos = quatloos_implicit; -		ensure(quatloos.value() == 1); +		ensure(quatloos == 1);  		quatloos += quatloos_implicit; -		ensure(quatloos.value() == 2); +		ensure(quatloos == 2);  		// math operations on implicits  		quatloos_implicit = 1; @@ -204,5 +209,11 @@ namespace tut  		S32 int_val = quatloos_implicit;  		ensure(int_val == 16); + +		// conversion of implicits +		LLUnitImplicit<F32, Latinum> latinum_implicit(2); +		ensure(latinum_implicit == 2); + +		ensure(latinum_implicit * 2 == quatloos_implicit);  	}  } | 
