summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorRichard Linden <none@none>2013-06-13 15:29:15 -0700
committerRichard Linden <none@none>2013-06-13 15:29:15 -0700
commit9fd3af3c389ed491b515cbb5136b344b069913e4 (patch)
tree79575b5483f940a57cbac168f175d03bce3eb969 /indra/llcommon
parentebf35d51b14f224c36a19a453a20885e667f6bec (diff)
SH-3931 WIP Interesting: Add graphs to visualize scene load metrics
changed Units macros and argument order to make it more clear optimized units for integer types fixed merging of periodicrecordings...should eliminate duplicate entries in sceneloadmonitor history
Diffstat (limited to 'indra/llcommon')
-rwxr-xr-xindra/llcommon/llcriticaldamp.cpp2
-rwxr-xr-xindra/llcommon/llcriticaldamp.h4
-rwxr-xr-xindra/llcommon/lldate.cpp2
-rwxr-xr-xindra/llcommon/lldate.h2
-rwxr-xr-xindra/llcommon/llfasttimer.cpp14
-rwxr-xr-xindra/llcommon/llfasttimer.h2
-rwxr-xr-xindra/llcommon/llprocessor.cpp2
-rwxr-xr-xindra/llcommon/llprocessor.h2
-rwxr-xr-xindra/llcommon/lltimer.cpp14
-rwxr-xr-xindra/llcommon/lltimer.h16
-rw-r--r--indra/llcommon/lltrace.h76
-rw-r--r--indra/llcommon/lltracerecording.cpp189
-rw-r--r--indra/llcommon/lltracerecording.h56
-rw-r--r--indra/llcommon/llunit.h372
-rw-r--r--indra/llcommon/tests/llunits_test.cpp104
15 files changed, 475 insertions, 382 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..809a0327ca 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
@@ -318,11 +318,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,7 +365,7 @@ 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_ms = last_frame_recording.getSum(*timerp);
U32 num_calls = last_frame_recording.getSum(timerp->callCount());
// Don't bother with really brief times, keep output concise
@@ -449,7 +449,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..fdc6997d45 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:
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..1bf853c5c0 100644
--- a/indra/llcommon/lltrace.h
+++ b/indra/llcommon/lltrace.h
@@ -44,27 +44,27 @@ 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;
void init();
void cleanup();
@@ -217,6 +217,11 @@ public:
size_t size() const
{
+ return getNumIndices();
+ }
+
+ static size_t getNumIndices()
+ {
return sNextStorageSlot;
}
@@ -263,6 +268,7 @@ public:
}
size_t getIndex() const { return mAccumulatorIndex; }
+ static size_t getNumIndices() { return AccumulatorBuffer<ACCUMULATOR>::getNumIndices(); }
virtual const char* getUnitLabel() { return ""; }
@@ -408,8 +414,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)
@@ -498,8 +504,8 @@ public:
void flush()
{
- 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;
if (mHasValue)
{
@@ -528,7 +534,7 @@ private:
F64 mMean,
mVarianceSum;
- LLUnitImplicit<LLUnits::Seconds, F64> mLastSampleTimeStamp,
+ LLUnitImplicit<F64, LLUnits::Seconds> mLastSampleTimeStamp,
mTotalSamplingTime;
U32 mNumSamples;
@@ -578,8 +584,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,8 +597,8 @@ 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();
@@ -672,7 +678,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(LLUnits::storageValue(converted_value));
}
template <typename T = F64>
@@ -694,7 +700,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(LLUnits::storageValue(converted_value));
}
template <typename T = F64>
@@ -716,7 +722,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(LLUnits::storageValue(converted_value));
}
@@ -739,8 +745,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()
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
index d32504b014..ff90da3822 100644
--- a/indra/llcommon/lltracerecording.cpp
+++ b/indra/llcommon/lltracerecording.cpp
@@ -186,26 +186,18 @@ 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();
@@ -213,7 +205,7 @@ LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumul
/ (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();
@@ -227,85 +219,85 @@ U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& sta
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();
@@ -341,7 +333,7 @@ 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;
}
@@ -430,6 +422,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 +436,20 @@ 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)
+{
+ // if I have a recording of any length, then close it off and start a fresh one
+ if (getCurRecording().getDuration().value())
+ {
+ nextPeriod();
+ }
+ getCurRecording().appendRecording(recording);
}
@@ -453,77 +457,77 @@ 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())
{
nextPeriod();
}
- getCurRecording().appendRecording(other_oldest_recording);
- if (other_recording_count > 1)
+ if (mAutoResize)
{
- if (mAutoResize)
+ S32 other_index = (other.mCurPeriod + 1) % other.mRecordingPeriods.size();
+ S32 end_index = (other.mCurPeriod) % other.mRecordingPeriods.size();
+
+ 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 +619,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 +647,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 +661,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 +675,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 +689,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 +704,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 +716,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 +738,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 +779,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..e3cef77b06 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -148,26 +148,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 +273,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 +288,7 @@ namespace LLTrace
class ThreadRecorder* getThreadRecorder();
LLTimer mSamplingTimer;
- F64 mElapsedSeconds;
+ LLUnit<F64, LLUnits::Seconds> mElapsedSeconds;
LLCopyOnWritePointer<RecordingBuffers> mBuffers;
};
@@ -299,11 +299,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 +318,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 +347,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 +363,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 +392,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 +408,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 +443,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 +469,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/llunit.h b/indra/llcommon/llunit.h
index f48cbe0e11..5b961c81f0 100644
--- a/indra/llcommon/llunit.h
+++ b/indra/llcommon/llunit.h
@@ -35,31 +35,31 @@ namespace LLUnits
{
template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE>
-struct ConversionFactor
+struct Convert
{
- static F64 get()
+ static VALUE_TYPE get(VALUE_TYPE val)
{
// 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;
+ return val;
}
};
template<typename BASE_UNITS_TAG, typename VALUE_TYPE>
-struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE>
+struct Convert<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE>
{
- static F64 get()
+ static VALUE_TYPE get(VALUE_TYPE val)
{
- return 1;
+ return val;
}
};
}
-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 +68,16 @@ struct LLUnit
{}
// unit initialization and conversion
- template<typename OTHER_UNIT, typename OTHER_STORAGE>
- LLUnit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ template<typename OTHER_STORAGE, typename OTHER_UNIT>
+ LLUnit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
: mValue(convert(other))
{}
+ bool operator == (const self_t& other)
+ {
+ return mValue = other.mValue;
+ }
+
// value assignment
self_t& operator = (storage_t value)
{
@@ -81,8 +86,8 @@ 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);
return *this;
@@ -93,9 +98,9 @@ struct LLUnit
return mValue;
}
- template<typename NEW_UNIT_TYPE> LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE> as()
+ template<typename NEW_UNIT_TYPE> LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE> as()
{
- return LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE>(*this);
+ return LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(*this);
}
@@ -104,8 +109,8 @@ 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);
}
@@ -115,8 +120,8 @@ 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);
}
@@ -127,7 +132,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 +144,43 @@ 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 storage_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());
+ return (storage_t)LLUnits::Convert<typename UNIT_TYPE::base_unit_t, UNIT_TYPE, STORAGE_TYPE>::get((STORAGE_TYPE)
+ LLUnits::Convert<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t, SOURCE_STORAGE>::get(v.value()));
}
+ template<typename SOURCE_STORAGE>
+ static storage_t convert(LLUnit<SOURCE_STORAGE, UNIT_TYPE> v)
+ {
+ return (storage_t)(v.value());
+ }
+
+
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))
{}
@@ -184,50 +195,50 @@ struct LLUnitImplicit : public LLUnit<UNIT_TYPE, STORAGE_TYPE>
//
// 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 +246,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 +297,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,7 +410,7 @@ 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(); }
};
@@ -411,70 +420,147 @@ struct LLGetUnitLabel<LLUnit<T, STORAGE_T> >
//
namespace LLUnits
{
+
+template<typename VALUE_TYPE>
+struct LinearOps
+{
+ typedef LinearOps<VALUE_TYPE> self_t;
+ LinearOps(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;
+ }
+};
+
+template<typename VALUE_TYPE>
+struct InverseLinearOps
+{
+ typedef InverseLinearOps<VALUE_TYPE> self_t;
+
+ InverseLinearOps(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;
+ }
+};
+
+
template<typename T>
-T rawValue(T val) { return val; }
+T storageValue(T val) { return val; }
template<typename UNIT_TYPE, typename STORAGE_TYPE>
-STORAGE_TYPE rawValue(LLUnit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
+STORAGE_TYPE storageValue(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); }
template<typename UNIT_TYPE, typename STORAGE_TYPE>
-STORAGE_TYPE rawValue(LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
+STORAGE_TYPE storageValue(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); }
-#define LL_DECLARE_DERIVED_UNIT(conversion_factor, base_unit_name, unit_name, unit_label) \
+#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> \
+struct Convert<unit_name, base_unit_name, STORAGE_TYPE> \
{ \
- static F64 get() \
+ static STORAGE_TYPE get(STORAGE_TYPE val) \
{ \
- return (F64)conversion_factor; \
+ return (LinearOps<STORAGE_TYPE>(val) conversion_operation).mValue; \
} \
}; \
\
template<typename STORAGE_TYPE> \
-struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \
+struct Convert<base_unit_name, unit_name, STORAGE_TYPE> \
{ \
- static F64 get() \
+ static STORAGE_TYPE get(STORAGE_TYPE val) \
{ \
- return (F64)(1.0 / (conversion_factor)); \
+ return (InverseLinearOps<STORAGE_TYPE>(val) 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; }}
-
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", Bytes, * 1000 * 1000);
+LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Bytes, * 1000 * 1000 * 1000);
+LL_DECLARE_DERIVED_UNIT(Kibibytes, "KiB", Bytes, * 1024);
+LL_DECLARE_DERIVED_UNIT(Mibibytes, "MiB", Bytes, * 1024 * 1024);
+LL_DECLARE_DERIVED_UNIT(Gibibytes, "GiB", Bytes, * 1024 * 1024 * 1024);
+
+LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, / 8);
+LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bytes, * (1000 / 8));
+LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Bytes, * (1000 / 8));
+LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Bytes, * (1000 * 1000 * 1000 / 8));
+LL_DECLARE_DERIVED_UNIT(Kibibits, "Kib", Bytes, * (1024 / 8));
+LL_DECLARE_DERIVED_UNIT(Mibibits, "Mib", Bytes, * (1024 / 8));
+LL_DECLARE_DERIVED_UNIT(Gibibits, "Gib", Bytes, * (1024 * 1024 * 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", Seconds, / 1000000);
+LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Seconds, / 1000000000);
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", Hertz, * 1000 * 1000);
+LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Hertz, * 1000 * 1000 * 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..747e8d1827 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", Quatloos, / 4);
}
namespace tut
@@ -53,105 +53,107 @@ 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<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 +161,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;