From 049317fc6442e8b2c2d93309a9d759aa063d2010 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Wed, 21 Aug 2013 23:51:46 -0700 Subject: SH-4433 WIP Interesting: Statistics > Ping Sim is always 0 ms added unit tests for lltrace --- indra/llcommon/tests/lltrace_test.cpp | 141 ++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 indra/llcommon/tests/lltrace_test.cpp (limited to 'indra/llcommon/tests/lltrace_test.cpp') diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp new file mode 100644 index 0000000000..1c2a4528ae --- /dev/null +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -0,0 +1,141 @@ +/** + * @file llsingleton_test.cpp + * @date 2011-08-11 + * @brief Unit test for the LLSingleton class + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltrace.h" +#include "lltracethreadrecorder.h" +#include "lltracerecording.h" +#include "../test/lltut.h" + +namespace LLUnits +{ + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Ounces, "oz"); + LL_DECLARE_DERIVED_UNIT(Ounces, * 12, TallCup, ""); + LL_DECLARE_DERIVED_UNIT(Ounces, * 16, GrandeCup, ""); + LL_DECLARE_DERIVED_UNIT(Ounces, * 20, VentiCup, ""); + + LL_DECLARE_BASE_UNIT(Grams, "g"); + LL_DECLARE_DERIVED_UNIT(Grams, / 1000, Milligrams, "mg"); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ounces); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, TallCup); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, GrandeCup); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, VentiCup); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Grams); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milligrams); + + +namespace tut +{ + using namespace LLTrace; + struct trace + { + ThreadRecorder mRecorder; + }; + + typedef test_group trace_t; + typedef trace_t::object trace_object_t; + tut::trace_t tut_singleton("LLTrace"); + + static CountStatHandle sCupsOfCoffeeConsumed("coffeeconsumed", "Delicious cup of dark roast."); + static SampleStatHandle sCaffeineLevelStat("caffeinelevel", "Coffee buzz quotient"); + static EventStatHandle sOuncesPerCup("cupsize", "Large, huge, or ginormous"); + + static F32 sCaffeineLevel(0.f); + const F32Milligrams sCaffeinePerOz(18.f); + + void drink_coffee(S32 num_cups, S32Ounces cup_size) + { + add(sCupsOfCoffeeConsumed, num_cups); + for (S32 i = 0; i < num_cups; i++) + { + record(sOuncesPerCup, cup_size); + } + + sCaffeineLevel += F32Ounces(num_cups * cup_size).value() * sCaffeinePerOz.value(); + sample(sCaffeineLevelStat, sCaffeineLevel); + } + + // basic data collection + template<> template<> + void trace_object_t::test<1>() + { + sample(sCaffeineLevelStat, sCaffeineLevel); + + Recording all_day; + Recording at_work; + Recording after_3pm; + + all_day.start(); + { + // warm up with one grande cup + drink_coffee(1, S32TallCup(1)); + + // go to work + at_work.start(); + { + // drink 3 tall cups, 1 after 3 pm + drink_coffee(2, S32GrandeCup(1)); + after_3pm.start(); + drink_coffee(1, S32GrandeCup(1)); + } + at_work.stop(); + drink_coffee(1, S32VentiCup(1)); + } + after_3pm.stop(); + all_day.stop(); + + ensure("count stats are counted when recording is active", + at_work.getSum(sCupsOfCoffeeConsumed) == 3 + && all_day.getSum(sCupsOfCoffeeConsumed) == 5 + && after_3pm.getSum(sCupsOfCoffeeConsumed) == 2); + ensure("measurement sums are counted when recording is active", + at_work.getSum(sOuncesPerCup) == S32Ounces(48) + && all_day.getSum(sOuncesPerCup) == S32Ounces(80) + && after_3pm.getSum(sOuncesPerCup) == S32Ounces(36)); + ensure("measurement min is specific to when recording is active", + at_work.getMin(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMin(sOuncesPerCup) == S32TallCup(1) + && after_3pm.getMin(sOuncesPerCup) == S32GrandeCup(1)); + ensure("measurement max is specific to when recording is active", + at_work.getMax(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMax(sOuncesPerCup) == S32VentiCup(1) + && after_3pm.getMax(sOuncesPerCup) == S32VentiCup(1)); + ensure("sample min is specific to when recording is active", + at_work.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1)).value() + && all_day.getMin(sCaffeineLevelStat) == F32Milligrams(0.f) + && after_3pm.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(2)).value()); + ensure("sample max is specific to when recording is active", + at_work.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3)).value() + && all_day.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value() + && after_3pm.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value()); + } + +} -- cgit v1.3 From a7aed07a5b620977fb74e4070e432eef01d11d3c Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Tue, 27 Aug 2013 13:41:19 -0700 Subject: broke out llunit.h into llunittype.h and llunits.h for unit declarations changed unit declarations macros to make a lot more sense --- indra/llcommon/CMakeLists.txt | 3 +- indra/llcommon/llcriticaldamp.h | 2 +- indra/llcommon/lldate.h | 2 +- indra/llcommon/llerror.h | 12 +- indra/llcommon/llfasttimer.cpp | 2 +- indra/llcommon/llmemory.h | 2 +- indra/llcommon/llpreprocessor.h | 6 +- indra/llcommon/llprocessor.h | 2 +- indra/llcommon/lltimer.h | 2 +- indra/llcommon/lltraceaccumulators.h | 2 +- indra/llcommon/llunit.h | 830 ---------------------------------- indra/llcommon/llunittype.h | 734 ++++++++++++++++++++++++++++++ indra/llcommon/tests/lltrace_test.cpp | 8 +- indra/llcommon/tests/llunits_test.cpp | 73 ++- indra/llmessage/llpacketack.h | 2 +- indra/llrender/llimagegl.h | 2 +- indra/newview/llappviewer.h | 2 +- indra/newview/llfasttimerview.h | 2 +- indra/newview/lltextureinfodetails.h | 2 +- 19 files changed, 830 insertions(+), 860 deletions(-) delete mode 100644 indra/llcommon/llunit.h create mode 100644 indra/llcommon/llunittype.h (limited to 'indra/llcommon/tests/lltrace_test.cpp') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 62880b07f6..e138a54d29 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -209,7 +209,8 @@ set(llcommon_HEADER_FILES lltracerecording.h lltracethreadrecorder.h lltreeiterators.h - llunit.h + llunits.h + llunittype.h lluri.h lluuid.h llwin32headers.h diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index a02a2a0dcf..1fb6a1af29 100755 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -31,7 +31,7 @@ #include #include "llframetimer.h" -#include "llunit.h" +#include "llunits.h" class LL_COMMON_API LLSmoothInterpolation { diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index aecf3b765e..be2cd2d051 100755 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -33,7 +33,7 @@ #include #include "stdtypes.h" -#include "llunit.h" +#include "llunits.h" /** * @class LLDate diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 0d6f1810d2..1ddb4874a0 100755 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -357,12 +357,12 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; #define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) // DEPRECATED: Use the new macros that allow tags and *look* like macros. -#define lldebugs LL_COMPILE_TIME_WARNING("Warning: lldebugs deprecated, use LL_DEBUGS() instead"); LL_DEBUGS() -#define llinfos LL_COMPILE_TIME_WARNING("Warning: llinfos deprecated, use LL_INFOS() instead"); LL_INFOS() -#define llwarns LL_COMPILE_TIME_WARNING("Warning: llwarns deprecated, use LL_WARNS() instead"); LL_WARNS() -#define llerrs LL_COMPILE_TIME_WARNING("Warning: llerrs deprecated, use LL_ERRS() instead"); LL_ERRS() -#define llcont LL_COMPILE_TIME_WARNING("Warning: llcont deprecated, use LL_CONT instead"); LL_CONT -#define llendl LL_COMPILE_TIME_WARNING("Warning: llendl deprecated, use LL_ENDL instead"); LL_ENDL +#define lldebugs LL_COMPILE_TIME_MESSAGE("Warning: lldebugs deprecated, use LL_DEBUGS() instead"); LL_DEBUGS() +#define llinfos LL_COMPILE_TIME_MESSAGE("Warning: llinfos deprecated, use LL_INFOS() instead"); LL_INFOS() +#define llwarns LL_COMPILE_TIME_MESSAGE("Warning: llwarns deprecated, use LL_WARNS() instead"); LL_WARNS() +#define llerrs LL_COMPILE_TIME_MESSAGE("Warning: llerrs deprecated, use LL_ERRS() instead"); LL_ERRS() +#define llcont LL_COMPILE_TIME_MESSAGE("Warning: llcont deprecated, use LL_CONT instead"); LL_CONT +#define llendl LL_COMPILE_TIME_MESSAGE("Warning: llendl deprecated, use LL_ENDL instead"); LL_ENDL #endif // LL_LLERROR_H diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index ae3234a87a..2235eb1a08 100755 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -32,7 +32,7 @@ #include "llsingleton.h" #include "lltreeiterators.h" #include "llsdserialize.h" -#include "llunit.h" +#include "llunits.h" #include "llsd.h" #include "lltracerecording.h" #include "lltracethreadrecorder.h" diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 23be1e5b2d..d3c5e5235d 100755 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -27,7 +27,7 @@ #define LLMEMORY_H #include "linden_common.h" -#include "llunit.h" +#include "llunits.h" #if !LL_WINDOWS #include #endif diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index f00885ae2f..0fcc872690 100755 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -193,12 +193,10 @@ #define LL_TO_STRING(x) LL_TO_STRING_HELPER(x) #define LL_FILE_LINENO(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg #if LL_WINDOWS -#define LL_COMPILE_TIME_WARNING(msg) __pragma(message(LL_FILE_LINENO(msg))) -#define LL_COMPILE_TIME_ERROR(msg) static_assert(false, msg) +#define LL_COMPILE_TIME_MESSAGE(msg) __pragma(message(LL_FILE_LINENO(msg))) #else // no way to get gcc 4.2 to print a user-defined diagnostic message only when a macro is used -#define LL_COMPILE_TIME_WARNING(msg) -#define LL_COMPILE_TIME_ERROR(msg) +#define LL_COMPILE_TIME_MESSAGE(msg) #endif #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 4956a39700..90e5bc59ee 100755 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -27,7 +27,7 @@ #ifndef LLPROCESSOR_H #define LLPROCESSOR_H -#include "llunit.h" +#include "llunits.h" class LLProcessorInfoImpl; diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 8b3930e2fa..4e58102094 100755 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -37,7 +37,7 @@ #include #include // units conversions -#include "llunit.h" +#include "llunits.h" #ifndef USEC_PER_SEC const U32 USEC_PER_SEC = 1000000; #endif diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index bf195f72b1..e0f60800e3 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -31,7 +31,7 @@ #include "stdtypes.h" #include "llpreprocessor.h" -#include "llunit.h" +#include "llunits.h" #include "lltimer.h" #include "llrefcount.h" #include "llthreadlocalstorage.h" diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h deleted file mode 100644 index 798d97a46e..0000000000 --- a/indra/llcommon/llunit.h +++ /dev/null @@ -1,830 +0,0 @@ -/** - * @file llunit.h - * @brief Unit conversion classes - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2012, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLUNIT_H -#define LL_LLUNIT_H - -#include "stdtypes.h" -#include "llpreprocessor.h" -#include "llerror.h" - -//lightweight replacement of type traits for simple type equality check -template -struct LLIsSameType -{ - static const bool value = false; -}; - -template -struct LLIsSameType -{ - static const bool value = true; -}; - -// workaround for decltype() not existing and typeof() not working inline in gcc 4.2 -template -struct LLResultTypeAdd -{ - typedef LL_TYPEOF(S() + T()) type_t; -}; - -template -struct LLResultTypeSubtract -{ - typedef LL_TYPEOF(S() - T()) type_t; -}; - -template -struct LLResultTypeMultiply -{ - typedef LL_TYPEOF(S() * T()) type_t; -}; - -template -struct LLResultTypeDivide -{ - typedef LL_TYPEOF(S() / T(1)) type_t; -}; - -template -struct LLResultTypePromote -{ - typedef LL_TYPEOF((true) ? S() : T()) type_t; -}; - -template -struct LLUnit -{ - typedef LLUnit self_t; - typedef STORAGE_TYPE storage_t; - - // value initialization - LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) - : mValue(value) - {} - - // unit initialization and conversion - template - LL_FORCE_INLINE LLUnit(LLUnit other) - : mValue(convert(other).mValue) - {} - - storage_t value() const - { - return mValue; - } - - void value(storage_t value) - { - mValue = value; - } - - template - storage_t valueInUnits() - { - return LLUnit(*this).value(); - } - - template - void valueInUnits(storage_t value) - { - *this = LLUnit(value); - } - - void operator += (self_t other) - { - mValue += convert(other).mValue; - } - - void operator -= (self_t other) - { - mValue -= convert(other).mValue; - } - - void operator *= (storage_t multiplicand) - { - mValue *= multiplicand; - } - - void operator *= (self_t multiplicand) - { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); - } - - void operator /= (storage_t divisor) - { - mValue /= divisor; - } - - void operator /= (self_t divisor) - { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); - } - - template - LL_FORCE_INLINE static self_t convert(LLUnit v) - { - typedef typename LLResultTypePromote::type_t result_storage_t; - LLUnit result; - result_storage_t divisor = ll_convert_units(v, result); - result.value(result.value() / divisor); - return self_t(result.value()); - } - -protected: - storage_t mValue; -}; - -template -std::ostream& operator <<(std::ostream& s, const LLUnit& unit) -{ - s << unit.value() << UNIT_TYPE::getUnitLabel(); - return s; -} - -template -std::istream& operator >>(std::istream& s, LLUnit& unit) -{ - STORAGE_TYPE val; - s >> val; - unit.value(val); - return s; -} - -template -struct LLUnitImplicit : public LLUnit -{ - typedef LLUnitImplicit self_t; - typedef typename LLUnit::storage_t storage_t; - typedef LLUnit base_t; - - LLUnitImplicit(storage_t value = storage_t()) - : base_t(value) - {} - - template - LLUnitImplicit(LLUnit other) - : base_t(other) - {} - - // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) - // this allows for interoperability with legacy code - operator storage_t() const - { - return base_t::value(); - } - - using base_t::operator +=; - void operator += (storage_t value) - { - base_t::mValue += value; - } - - // this overload exists to explicitly catch use of another implicit unit - // without ambiguity between conversion to storage_t vs conversion to base_t - template - void operator += (LLUnitImplicit other) - { - base_t::mValue += convert(other).value(); - } - - using base_t::operator -=; - void operator -= (storage_t value) - { - base_t::mValue -= value; - } - - // this overload exists to explicitly catch use of another implicit unit - // without ambiguity between conversion to storage_t vs conversion to base_t - template - void operator -= (LLUnitImplicit other) - { - base_t::mValue -= convert(other).value(); - } - -}; - -template -std::ostream& operator <<(std::ostream& s, const LLUnitImplicit& unit) -{ - s << unit.value() << UNIT_TYPE::getUnitLabel(); - return s; -} - -template -std::istream& operator >>(std::istream& s, LLUnitImplicit& unit) -{ - STORAGE_TYPE val; - s >> val; - unit = val; - return s; -} - -template -LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) -{ - S2 divisor(1); - - LL_STATIC_ASSERT((LLIsSameType::value - || !LLIsSameType::value - || !LLIsSameType::value), - "conversion requires compatible units"); - - if (LLIsSameType::value) - { - // T1 and T2 same type, just assign - out.value((S2)in.value()); - } - else if (T1::sLevel > T2::sLevel) - { - // reduce T1 - LLUnit new_in; - divisor *= (S2)ll_convert_units(in, new_in); - divisor *= (S2)ll_convert_units(new_in, out); - } - else - { - // reduce T2 - LLUnit new_out; - divisor *= (S2)ll_convert_units(in, new_out); - divisor *= (S2)ll_convert_units(new_out, out); - } - return divisor; -} - -template -struct LLStorageType -{ - typedef T type_t; -}; - -template -struct LLStorageType > -{ - typedef STORAGE_TYPE type_t; -}; - -// all of these operators need to perform type promotion on the storage type of the units, so they -// cannot be expressed as operations on identical types with implicit unit conversion -// e.g. typeof(S32Bytes(x) + F32Megabytes(y)) <==> F32Bytes - -// -// operator + -// -template -LLUnit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnit second) -{ - LLUnit::type_t, UNIT_TYPE1> result(first); - result += second; - return result; -} - -template -LLUnit operator + (LLUnit first, UNITLESS second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnit operator + (UNITLESS first, LLUnit second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result += second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result += second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result += LLUnitImplicit(second); - return result; -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator + (LLUnitImplicit first, UNITLESS_TYPE second) -{ - LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); - result += second; - return result; -} - -template -LLUnitImplicit::type_t, STORAGE_TYPE>:: - type_t, UNIT_TYPE> operator + (UNITLESS_TYPE first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); - result += second; - return result; -} - -// -// operator - -// -template -LLUnit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnit second) -{ - LLUnit::type_t, UNIT_TYPE1> result(first); - result -= second; - return result; -} - -template -LLUnit operator - (LLUnit first, UNITLESS second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnit operator - (UNITLESS first, LLUnit second) -{ - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit(0); -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result -= second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result -= second; - return result; -} - -template -LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnit second) -{ - LLUnitImplicit::type_t, UNIT_TYPE1> result(first); - result -= LLUnitImplicit(second); - return result; -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator - (LLUnitImplicit first, UNITLESS_TYPE second) -{ - LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); - result -= second; - return result; -} - -template -LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator - (UNITLESS_TYPE first, LLUnitImplicit second) -{ - LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); - result -= second; - return result; -} - -// -// operator * -// -template -LLUnit operator * (LLUnit, LLUnit) -{ - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); - return LLUnit(); -} - -template -LLUnit::type_t>::type_t, UNIT_TYPE> operator * (LLUnit first, UNITLESS_TYPE second) -{ - return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() * second); -} - -template -LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnit second) -{ - return LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); -} - -template -LLUnitImplicit operator * (LLUnitImplicit, LLUnitImplicit) -{ - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); - return LLUnitImplicit(); -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator * (LLUnitImplicit first, UNITLESS_TYPE second) -{ - return LLUnitImplicit::type_t, UNIT_TYPE>(first.value() * second); -} - -template -LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnitImplicit second) -{ - return LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); -} - - -// -// operator / -// - -template -LLUnit::type_t>::type_t, UNIT_TYPE> operator / (LLUnit first, UNITLESS_TYPE second) -{ - return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() / second); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnit second) -{ - return first.value() / first.convert(second).value(); -} - -template -LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator / (LLUnitImplicit first, UNITLESS_TYPE second) -{ - return LLUnitImplicit::type_t>::type_t, UNIT_TYPE>(first.value() / second); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnitImplicit second) -{ - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnitImplicit second) -{ - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); -} - -template -typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnit second) -{ - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); -} - -// -// comparison operators -// - -#define LL_UNIT_DECLARE_COMPARISON_OPERATOR(op) \ -template \ -bool operator op (LLUnitImplicit first, LLUnitImplicit second) \ -{ \ - return first.value() op first.convert(second).value(); \ -} \ - \ -template \ -bool operator op (LLUnitImplicit first, UNITLESS_TYPE second) \ -{ \ - return first.value() op second; \ -} \ - \ -template \ -bool operator op (UNITLESS_TYPE first, LLUnitImplicit second) \ -{ \ - return first op second.value(); \ -} \ - \ -template \ -bool operator op (LLUnit first, LLUnit second) \ -{ \ - return first.value() op first.convert(second).value(); \ -} \ - \ -template \ -bool operator op (LLUnit first, UNITLESS_TYPE second) \ -{ \ - LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ - return false; \ -} \ - \ -template \ -bool operator op (UNITLESS_TYPE first, LLUnit second) \ -{ \ - LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ - return false; \ -} \ - \ -template \ -bool operator op (LLUnit first, LLUnitImplicit second) \ -{ \ - return first.value() op first.convert(second).value(); \ -} \ - \ -template \ -bool operator op (LLUnitImplicit first, LLUnit second) \ -{ \ - return first.value() op first.convert(second).value(); \ -} - -LL_UNIT_DECLARE_COMPARISON_OPERATOR(<); -LL_UNIT_DECLARE_COMPARISON_OPERATOR(<=); -LL_UNIT_DECLARE_COMPARISON_OPERATOR(>); -LL_UNIT_DECLARE_COMPARISON_OPERATOR(>=); -LL_UNIT_DECLARE_COMPARISON_OPERATOR(==); -LL_UNIT_DECLARE_COMPARISON_OPERATOR(!=); - - -template -struct LLGetUnitLabel -{ - static const char* getUnitLabel() { return ""; } -}; - -template -struct LLGetUnitLabel > -{ - static const char* getUnitLabel() { return T::getUnitLabel(); } -}; - -template -struct LLUnitLinearOps -{ - typedef LLUnitLinearOps self_t; - - LLUnitLinearOps(T val) - : mValue(val), - mDivisor(1) - {} - - template - self_t operator * (OTHER_T other) - { - return mValue * other; - } - - template - self_t operator / (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template - self_t operator + (OTHER_T other) - { - mValue /= mDivisor; - mValue += other; - return *this; - } - - template - self_t operator - (OTHER_T other) - { - mValue /= mDivisor; - mValue -= other; - return *this; - } - - T mValue; - T mDivisor; -}; - -template -struct LLUnitInverseLinearOps -{ - typedef LLUnitInverseLinearOps self_t; - - LLUnitInverseLinearOps(T val) - : mValue(val), - mDivisor(1) - {} - - template - self_t operator * (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template - self_t operator / (OTHER_T other) - { - mValue *= other; - return *this; - } - - template - self_t operator + (OTHER_T other) - { - mValue /= mDivisor; - mValue -= other; - return *this; - } - - template - self_t operator - (OTHER_T other) - { - mValue /= mDivisor; - mValue += other; - return *this; - } - - T mValue; - T mDivisor; -}; - -#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ -struct base_unit_name \ -{ \ - static const int sLevel = 0; \ - typedef base_unit_name base_unit_t; \ - static const char* getUnitLabel() { return unit_label; } \ - template \ - static LLUnit fromValue(T value) { return LLUnit(value); } \ - template \ - static LLUnit fromValue(LLUnit value) \ - { return LLUnit(value); } \ -} - - -#define LL_DECLARE_DERIVED_UNIT(base_unit_name, conversion_operation, unit_name, unit_label) \ -struct unit_name \ -{ \ - static const int sLevel = base_unit_name::sLevel + 1; \ - typedef base_unit_name base_unit_t; \ - static const char* getUnitLabel() { return unit_label; } \ - template \ - static LLUnit fromValue(T value) { return LLUnit(value); } \ - template \ - static LLUnit fromValue(LLUnit value) \ - { return LLUnit(value); } \ -}; \ - \ -template \ -LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ -{ \ - typedef typename LLResultTypePromote::type_t result_storage_t; \ - LLUnitLinearOps op = \ - LLUnitLinearOps(in.value()) conversion_operation; \ - out = LLUnit((S2)op.mValue); \ - return op.mDivisor; \ -} \ - \ -template \ -LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ -{ \ - typedef typename LLResultTypePromote::type_t result_storage_t; \ - LLUnitInverseLinearOps op = \ - LLUnitInverseLinearOps(in.value()) conversion_operation; \ - out = LLUnit((S2)op.mValue); \ - return op.mDivisor; \ -} - -#define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ - typedef LLUnit F32##unit_name; \ - typedef LLUnitImplicit F32##unit_name##Implicit;\ - typedef LLUnit F64##unit_name; \ - typedef LLUnitImplicit F64##unit_name##Implicit;\ - typedef LLUnit S32##unit_name; \ - typedef LLUnitImplicit S32##unit_name##Implicit;\ - typedef LLUnit S64##unit_name; \ - typedef LLUnitImplicit S64##unit_name##Implicit;\ - typedef LLUnit U32##unit_name; \ - typedef LLUnitImplicit U32##unit_name##Implicit;\ - typedef LLUnit U64##unit_name; \ - typedef LLUnitImplicit U64##unit_name##Implicit - -// -// Unit declarations -// - -namespace LLUnits -{ -LL_DECLARE_BASE_UNIT(Bytes, "B"); -// technically, these are kibibytes, mibibytes, etc. but we should stick with commonly accepted terminology -LL_DECLARE_DERIVED_UNIT(Bytes, * 1024, Kilobytes, "KB"); -LL_DECLARE_DERIVED_UNIT(Kilobytes, * 1024, Megabytes, "MB"); -LL_DECLARE_DERIVED_UNIT(Megabytes, * 1024, Gigabytes, "GB"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bytes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobytes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabytes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabytes); - -namespace LLUnits -{ -// technically, these are kibibits, mibibits, etc. but we should stick with commonly accepted terminology -LL_DECLARE_DERIVED_UNIT(Bytes, / 8, Bits, "b"); -LL_DECLARE_DERIVED_UNIT(Bits, * 1024, Kilobits, "Kb"); -LL_DECLARE_DERIVED_UNIT(Kilobits, * 1024, Megabits, "Mb"); -LL_DECLARE_DERIVED_UNIT(Megabits, * 1024, Gigabits, "Gb"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bits); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobits); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabits); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabits); - -namespace LLUnits -{ -LL_DECLARE_BASE_UNIT(Seconds, "s"); -LL_DECLARE_DERIVED_UNIT(Seconds, * 60, Minutes, "min"); -LL_DECLARE_DERIVED_UNIT(Minutes, * 60, Hours, "h"); -LL_DECLARE_DERIVED_UNIT(Hours, * 24, Days, "d"); -LL_DECLARE_DERIVED_UNIT(Seconds, / 1000, Milliseconds, "ms"); -LL_DECLARE_DERIVED_UNIT(Milliseconds, / 1000, Microseconds, "\x09\x3cs"); -LL_DECLARE_DERIVED_UNIT(Microseconds, / 1000, Nanoseconds, "ns"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Seconds); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Minutes); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hours); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Days); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milliseconds); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Microseconds); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Nanoseconds); - -namespace LLUnits -{ -LL_DECLARE_BASE_UNIT(Meters, "m"); -LL_DECLARE_DERIVED_UNIT(Meters, * 1000, Kilometers, "km"); -LL_DECLARE_DERIVED_UNIT(Meters, / 100, Centimeters, "cm"); -LL_DECLARE_DERIVED_UNIT(Meters, / 1000, Millimeters, "mm"); -} - -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Meters); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilometers); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Centimeters); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Millimeters); - -namespace LLUnits -{ -// rare units -LL_DECLARE_BASE_UNIT(Hertz, "Hz"); -LL_DECLARE_DERIVED_UNIT(Hertz, * 1000, Kilohertz, "KHz"); -LL_DECLARE_DERIVED_UNIT(Kilohertz, * 1000, Megahertz, "MHz"); -LL_DECLARE_DERIVED_UNIT(Megahertz, * 1000, Gigahertz, "GHz"); - -LL_DECLARE_BASE_UNIT(Radians, "rad"); -LL_DECLARE_DERIVED_UNIT(Radians, / 57.29578f, Degrees, "deg"); - -LL_DECLARE_BASE_UNIT(Percent, "%"); -LL_DECLARE_DERIVED_UNIT(Percent, * 100, Ratio, "x"); - -LL_DECLARE_BASE_UNIT(Triangles, "tris"); -LL_DECLARE_DERIVED_UNIT(Triangles, * 1000, Kilotriangles, "ktris"); - -} // namespace LLUnits - -// rare units -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilohertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megahertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigahertz); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Radians); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Degrees); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Percent); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ratio); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Triangles); -LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilotriangles); - - -#endif // LL_LLUNIT_H diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h new file mode 100644 index 0000000000..949e4492c7 --- /dev/null +++ b/indra/llcommon/llunittype.h @@ -0,0 +1,734 @@ +/** + * @file llunit.h + * @brief Unit conversion classes + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_UNITTYPE_H +#define LL_UNITTYPE_H + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llerror.h" + +//lightweight replacement of type traits for simple type equality check +template +struct LLIsSameType +{ + static const bool value = false; +}; + +template +struct LLIsSameType +{ + static const bool value = true; +}; + +// workaround for decltype() not existing and typeof() not working inline in gcc 4.2 +template +struct LLResultTypeAdd +{ + typedef LL_TYPEOF(S() + T()) type_t; +}; + +template +struct LLResultTypeSubtract +{ + typedef LL_TYPEOF(S() - T()) type_t; +}; + +template +struct LLResultTypeMultiply +{ + typedef LL_TYPEOF(S() * T()) type_t; +}; + +template +struct LLResultTypeDivide +{ + typedef LL_TYPEOF(S() / T(1)) type_t; +}; + +template +struct LLResultTypePromote +{ + typedef LL_TYPEOF((true) ? S() : T()) type_t; +}; + +template +struct LLUnit +{ + typedef LLUnit self_t; + typedef STORAGE_TYPE storage_t; + + // value initialization + LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + // unit initialization and conversion + template + LL_FORCE_INLINE LLUnit(LLUnit other) + : mValue(convert(other).mValue) + {} + + storage_t value() const + { + return mValue; + } + + void value(storage_t value) + { + mValue = value; + } + + template + storage_t valueInUnits() + { + return LLUnit(*this).value(); + } + + template + void valueInUnits(storage_t value) + { + *this = LLUnit(value); + } + + void operator += (self_t other) + { + mValue += convert(other).mValue; + } + + void operator -= (self_t other) + { + mValue -= convert(other).mValue; + } + + void operator *= (storage_t multiplicand) + { + mValue *= multiplicand; + } + + void operator *= (self_t multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); + } + + void operator /= (storage_t divisor) + { + mValue /= divisor; + } + + void operator /= (self_t divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); + } + + template + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + typedef typename LLResultTypePromote::type_t result_storage_t; + LLUnit result; + result_storage_t divisor = ll_convert_units(v, result); + result.value(result.value() / divisor); + return self_t(result.value()); + } + +protected: + storage_t mValue; +}; + +template +std::ostream& operator <<(std::ostream& s, const LLUnit& unit) +{ + s << unit.value() << UNIT_TYPE::getUnitLabel(); + return s; +} + +template +std::istream& operator >>(std::istream& s, LLUnit& unit) +{ + STORAGE_TYPE val; + s >> val; + unit.value(val); + return s; +} + +template +struct LLUnitImplicit : public LLUnit +{ + typedef LLUnitImplicit self_t; + typedef typename LLUnit::storage_t storage_t; + typedef LLUnit base_t; + + LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template + LLUnitImplicit(LLUnit other) + : base_t(other) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) + // this allows for interoperability with legacy code + operator storage_t() const + { + return base_t::value(); + } + + using base_t::operator +=; + void operator += (storage_t value) + { + base_t::mValue += value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template + void operator += (LLUnitImplicit other) + { + base_t::mValue += convert(other).value(); + } + + using base_t::operator -=; + void operator -= (storage_t value) + { + base_t::mValue -= value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template + void operator -= (LLUnitImplicit other) + { + base_t::mValue -= convert(other).value(); + } + +}; + +template +std::ostream& operator <<(std::ostream& s, const LLUnitImplicit& unit) +{ + s << unit.value() << UNIT_TYPE::getUnitLabel(); + return s; +} + +template +std::istream& operator >>(std::istream& s, LLUnitImplicit& unit) +{ + STORAGE_TYPE val; + s >> val; + unit = val; + return s; +} + +template +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) +{ + S2 divisor(1); + + LL_STATIC_ASSERT((LLIsSameType::value + || !LLIsSameType::value + || !LLIsSameType::value), + "conversion requires compatible units"); + + if (LLIsSameType::value) + { + // T1 and T2 same type, just assign + out.value((S2)in.value()); + } + else if (T1::sLevel > T2::sLevel) + { + // reduce T1 + LLUnit new_in; + divisor *= (S2)ll_convert_units(in, new_in); + divisor *= (S2)ll_convert_units(new_in, out); + } + else + { + // reduce T2 + LLUnit new_out; + divisor *= (S2)ll_convert_units(in, new_out); + divisor *= (S2)ll_convert_units(new_out, out); + } + return divisor; +} + +template +struct LLStorageType +{ + typedef T type_t; +}; + +template +struct LLStorageType > +{ + typedef STORAGE_TYPE type_t; +}; + +// all of these operators need to perform type promotion on the storage type of the units, so they +// cannot be expressed as operations on identical types with implicit unit conversion +// e.g. typeof(S32Bytes(x) + F32Megabytes(y)) <==> F32Bytes + +// +// operator + +// +template +LLUnit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnit second) +{ + LLUnit::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template +LLUnit operator + (LLUnit first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnit operator + (UNITLESS first, LLUnit second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator + (LLUnitImplicit first, LLUnit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result += LLUnitImplicit(second); + return result; +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator + (LLUnitImplicit first, UNITLESS_TYPE second) +{ + LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); + result += second; + return result; +} + +template +LLUnitImplicit::type_t, STORAGE_TYPE>:: + type_t, UNIT_TYPE> operator + (UNITLESS_TYPE first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); + result += second; + return result; +} + +// +// operator - +// +template +LLUnit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnit second) +{ + LLUnit::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template +LLUnit operator - (LLUnit first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnit operator - (UNITLESS first, LLUnit second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnit first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template +LLUnitImplicit::type_t, UNIT_TYPE1> operator - (LLUnitImplicit first, LLUnit second) +{ + LLUnitImplicit::type_t, UNIT_TYPE1> result(first); + result -= LLUnitImplicit(second); + return result; +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator - (LLUnitImplicit first, UNITLESS_TYPE second) +{ + LLUnitImplicit::type_t>::type_t, UNIT_TYPE> result(first); + result -= second; + return result; +} + +template +LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator - (UNITLESS_TYPE first, LLUnitImplicit second) +{ + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> result(first); + result -= second; + return result; +} + +// +// operator * +// +template +LLUnit operator * (LLUnit, LLUnit) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnit(); +} + +template +LLUnit::type_t>::type_t, UNIT_TYPE> operator * (LLUnit first, UNITLESS_TYPE second) +{ + return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() * second); +} + +template +LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnit second) +{ + return LLUnit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); +} + +template +LLUnitImplicit operator * (LLUnitImplicit, LLUnitImplicit) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit(); +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator * (LLUnitImplicit first, UNITLESS_TYPE second) +{ + return LLUnitImplicit::type_t, UNIT_TYPE>(first.value() * second); +} + +template +LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE> operator * (UNITLESS_TYPE first, LLUnitImplicit second) +{ + return LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNIT_TYPE>(first * second.value()); +} + + +// +// operator / +// + +template +LLUnit::type_t>::type_t, UNIT_TYPE> operator / (LLUnit first, UNITLESS_TYPE second) +{ + return LLUnit::type_t>::type_t, UNIT_TYPE>(first.value() / second); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnit second) +{ + return first.value() / first.convert(second).value(); +} + +template +LLUnitImplicit::type_t>::type_t, UNIT_TYPE> operator / (LLUnitImplicit first, UNITLESS_TYPE second) +{ + return LLUnitImplicit::type_t>::type_t, UNIT_TYPE>(first.value() / second); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnitImplicit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnitImplicit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +template +typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnit second) +{ + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); +} + +// +// comparison operators +// + +#define LL_UNIT_DECLARE_COMPARISON_OPERATOR(op) \ +template \ +bool operator op (LLUnitImplicit first, LLUnitImplicit second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template \ +bool operator op (LLUnitImplicit first, UNITLESS_TYPE second) \ +{ \ + return first.value() op second; \ +} \ + \ +template \ +bool operator op (UNITLESS_TYPE first, LLUnitImplicit second) \ +{ \ + return first op second.value(); \ +} \ + \ +template \ +bool operator op (LLUnit first, LLUnit second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template \ +bool operator op (LLUnit first, UNITLESS_TYPE second) \ +{ \ + LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ + return false; \ +} \ + \ +template \ +bool operator op (UNITLESS_TYPE first, LLUnit second) \ +{ \ + LL_BAD_TEMPLATE_INSTANTIATION(UNITLESS_TYPE, "operator " #op " requires compatible unit types"); \ + return false; \ +} \ + \ +template \ +bool operator op (LLUnit first, LLUnitImplicit second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} \ + \ +template \ +bool operator op (LLUnitImplicit first, LLUnit second) \ +{ \ + return first.value() op first.convert(second).value(); \ +} + +LL_UNIT_DECLARE_COMPARISON_OPERATOR(<); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(<=); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(>); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(>=); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(==); +LL_UNIT_DECLARE_COMPARISON_OPERATOR(!=); + + +template +struct LLGetUnitLabel +{ + static const char* getUnitLabel() { return ""; } +}; + +template +struct LLGetUnitLabel > +{ + static const char* getUnitLabel() { return T::getUnitLabel(); } +}; + +template +struct LLUnitLinearOps +{ + typedef LLUnitLinearOps self_t; + + LLUnitLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template + self_t operator * (OTHER_T other) + { + return mValue * other; + } + + template + self_t operator / (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue /= mDivisor; + mValue += other; + return *this; + } + + template + self_t operator - (OTHER_T other) + { + mValue /= mDivisor; + mValue -= other; + return *this; + } + + T mValue; + T mDivisor; +}; + +template +struct LLUnitInverseLinearOps +{ + typedef LLUnitInverseLinearOps self_t; + + LLUnitInverseLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template + self_t operator * (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator / (OTHER_T other) + { + mValue *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue /= mDivisor; + mValue -= other; + return *this; + } + + template + self_t operator - (OTHER_T other) + { + mValue /= mDivisor; + mValue += other; + return *this; + } + + T mValue; + T mDivisor; +}; + +#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ +struct base_unit_name \ +{ \ + static const int sLevel = 0; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(value); } \ +} + + +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ +struct unit_name \ +{ \ + static const int sLevel = base_unit_name::sLevel + 1; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(value); } \ +}; \ + \ +template \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ +{ \ + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitInverseLinearOps op = \ + LLUnitInverseLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)op.mValue); \ + return op.mDivisor; \ +} \ + \ +template \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ +{ \ + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitLinearOps op = \ + LLUnitLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)op.mValue); \ + return op.mDivisor; \ +} + +#define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ + typedef LLUnit F32##unit_name; \ + typedef LLUnitImplicit F32##unit_name##Implicit;\ + typedef LLUnit F64##unit_name; \ + typedef LLUnitImplicit F64##unit_name##Implicit;\ + typedef LLUnit S32##unit_name; \ + typedef LLUnitImplicit S32##unit_name##Implicit;\ + typedef LLUnit S64##unit_name; \ + typedef LLUnitImplicit S64##unit_name##Implicit;\ + typedef LLUnit U32##unit_name; \ + typedef LLUnitImplicit U32##unit_name##Implicit;\ + typedef LLUnit U64##unit_name; \ + typedef LLUnitImplicit U64##unit_name##Implicit + +#endif //LL_UNITTYPE_H diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp index 1c2a4528ae..8ce509699d 100644 --- a/indra/llcommon/tests/lltrace_test.cpp +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -36,12 +36,12 @@ namespace LLUnits { // using powers of 2 to allow strict floating point equality LL_DECLARE_BASE_UNIT(Ounces, "oz"); - LL_DECLARE_DERIVED_UNIT(Ounces, * 12, TallCup, ""); - LL_DECLARE_DERIVED_UNIT(Ounces, * 16, GrandeCup, ""); - LL_DECLARE_DERIVED_UNIT(Ounces, * 20, VentiCup, ""); + LL_DECLARE_DERIVED_UNIT(TallCup, "", Ounces, / 12); + LL_DECLARE_DERIVED_UNIT(GrandeCup, "", Ounces, / 16); + LL_DECLARE_DERIVED_UNIT(VentiCup, "", Ounces, / 20); LL_DECLARE_BASE_UNIT(Grams, "g"); - LL_DECLARE_DERIVED_UNIT(Grams, / 1000, Milligrams, "mg"); + LL_DECLARE_DERIVED_UNIT(Milligrams, "mg", Grams, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ounces); diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp index 31d4f86159..5a18603e4e 100644 --- a/indra/llcommon/tests/llunits_test.cpp +++ b/indra/llcommon/tests/llunits_test.cpp @@ -27,15 +27,15 @@ #include "linden_common.h" -#include "llunit.h" +#include "llunits.h" #include "../test/lltut.h" namespace LLUnits { // using powers of 2 to allow strict floating point equality LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); - LL_DECLARE_DERIVED_UNIT(Quatloos, * 4, Latinum, "Lat"); - LL_DECLARE_DERIVED_UNIT(Latinum, / 16, Solari, "Sol"); + LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); + LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Quatloos); @@ -256,6 +256,12 @@ namespace tut // conversion of implicits LLUnitImplicit latinum_implicit(2); ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); + + quatloos_implicit += F32Quatloos(10); + ensure("can add-assign explicit units", quatloos_implicit == 26); + + quatloos_implicit -= F32Quatloos(10); + ensure("can subtract-assign explicit units", quatloos_implicit == 16); } // precision tests @@ -272,4 +278,65 @@ namespace tut mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); } + + // default units + template<> template<> + void units_object_t::test<9>() + { + U32Gigabytes GB(1); + U32Megabytes MB(GB); + U32Kilobytes KB(GB); + U32Bytes B(GB); + + ensure("GB -> MB conversion", MB.value() == 1024); + ensure("GB -> KB conversion", KB.value() == 1024 * 1024); + ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); + + KB = U32Kilobytes(1); + U32Kilobits Kb(KB); + U32Bits b(KB); + ensure("KB -> Kb conversion", Kb.value() == 8); + ensure("KB -> b conversion", b.value() == 8 * 1024); + + U32Days days(1); + U32Hours hours(days); + U32Minutes minutes(days); + U32Seconds seconds(days); + U32Milliseconds ms(days); + + ensure("days -> hours conversion", hours.value() == 24); + ensure("days -> minutes conversion", minutes.value() == 24 * 60); + ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); + ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); + + U32Kilometers km(1); + U32Meters m(km); + U32Centimeters cm(km); + U32Millimeters mm(km); + + ensure("km -> m conversion", m.value() == 1000); + ensure("km -> cm conversion", cm.value() == 1000 * 100); + ensure("km -> mm conversion", mm.value() == 1000 * 1000); + + U32Gigahertz GHz(1); + U32Megahertz MHz(GHz); + U32Kilohertz KHz(GHz); + U32Hertz Hz(GHz); + + ensure("GHz -> MHz conversion", MHz.value() == 1000); + ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); + ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); + + F32Radians rad(6.2831853071795f); + F32Degrees deg(rad); + ensure("radians -> degrees conversion", deg.value() > 359 && deg.value() < 361); + + F32Percent percent(50); + F32Ratio ratio(percent); + ensure("percent -> ratio conversion", ratio.value() == 0.5f); + + U32Kilotriangles ktris(1); + U32Triangles tris(ktris); + ensure("kilotriangles -> triangles conversion", tris.value() == 1000); + } } diff --git a/indra/llmessage/llpacketack.h b/indra/llmessage/llpacketack.h index f55d5246f6..f0ed923f19 100755 --- a/indra/llmessage/llpacketack.h +++ b/indra/llmessage/llpacketack.h @@ -28,7 +28,7 @@ #define LL_LLPACKETACK_H #include "llhost.h" -#include "llunit.h" +#include "llunits.h" class LLReliablePacketParams { diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 5e027851f3..09ea8a1124 100755 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -34,7 +34,7 @@ #include "llpointer.h" #include "llrefcount.h" #include "v2math.h" -#include "llunit.h" +#include "llunits.h" #include "llrender.h" class LLTextureAtlas ; diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 6b16a96c11..d642d55b14 100755 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -32,7 +32,7 @@ #include "llsys.h" // for LLOSInfo #include "lltimer.h" #include "llappcorehttp.h" -#include "llunit.h" +#include "llunits.h" class LLCommandLineParser; class LLFrameTimer; diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h index 8c2c939c5e..8c8eb99b59 100755 --- a/indra/newview/llfasttimerview.h +++ b/indra/newview/llfasttimerview.h @@ -29,7 +29,7 @@ #include "llfloater.h" #include "llfasttimer.h" -#include "llunit.h" +#include "llunits.h" #include "lltracerecording.h" #include diff --git a/indra/newview/lltextureinfodetails.h b/indra/newview/lltextureinfodetails.h index 7cba87e5a8..a42c335035 100755 --- a/indra/newview/lltextureinfodetails.h +++ b/indra/newview/lltextureinfodetails.h @@ -28,7 +28,7 @@ #define LL_LLTEXTUREINFODETAILS_H #include "lluuid.h" -#include "llunit.h" +#include "llunits.h" struct LLTextureInfoDetails { -- cgit v1.3 From 1dfba44b3dc14564c99333dedb7a380a160aee44 Mon Sep 17 00:00:00 2001 From: Richard Linden Date: Mon, 21 Oct 2013 14:22:21 -0700 Subject: fixed things so that trace recordings can be read from even while active --- indra/llcommon/lltraceaccumulators.cpp | 102 ++++++----- indra/llcommon/lltraceaccumulators.h | 8 +- indra/llcommon/lltracerecording.cpp | 279 +++++++++++++++++++++++++------ indra/llcommon/lltracerecording.h | 2 +- indra/llcommon/lltracethreadrecorder.cpp | 3 +- indra/llcommon/lltracethreadrecorder.h | 2 +- indra/llcommon/tests/lltrace_test.cpp | 5 +- 7 files changed, 299 insertions(+), 102 deletions(-) (limited to 'indra/llcommon/tests/lltrace_test.cpp') diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index 7d0e63e76a..385d31edd7 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -155,6 +155,39 @@ void AccumulatorBufferGroup::sync() } } +F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b) +{ + const F64 epsilon = 0.0000001; + + if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.getSamplingTime(), + n_2 = b.getSamplingTime(); + F64 m_1 = a.getMean(), + m_2 = b.getMean(); + F64 v_1 = a.getSumOfSquares() / a.getSamplingTime(), + v_2 = b.getSumOfSquares() / b.getSamplingTime(); + if (n_1 < epsilon) + { + return b.getSumOfSquares(); + } + else + { + return a.getSamplingTime() + * ((((n_1 - epsilon) * v_1) + + ((n_2 - epsilon) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - epsilon)); + } + } + + return a.getSumOfSquares(); +} + + void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type ) { if (append_type == NON_SEQUENTIAL) @@ -180,37 +213,8 @@ void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppen if (other.mMin < mMin) { mMin = other.mMin; } if (other.mMax > mMax) { mMax = other.mMax; } - F64 epsilon = 0.0000001; + mSumOfSquares = mergeSumsOfSquares(*this, other); - if (other.mTotalSamplingTime > epsilon && mTotalSamplingTime > epsilon) - { - // combine variance (and hence standard deviation) of 2 different sized sample groups using - // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm - F64 n_1 = mTotalSamplingTime, - n_2 = other.mTotalSamplingTime; - F64 m_1 = mMean, - m_2 = other.mMean; - F64 v_1 = mSumOfSquares / mTotalSamplingTime, - v_2 = other.mSumOfSquares / other.mTotalSamplingTime; - if (n_1 < epsilon) - { - mSumOfSquares = other.mSumOfSquares; - } - else - { - mSumOfSquares = mTotalSamplingTime - * ((((n_1 - epsilon) * v_1) - + ((n_2 - epsilon) * v_2) - + (((n_1 * n_2) / (n_1 + n_2)) - * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) - / (n_1 + n_2 - epsilon)); - } - - F64 weight = mTotalSamplingTime / (mTotalSamplingTime + other.mTotalSamplingTime); - mNumSamples += other.mNumSamples; - mTotalSamplingTime += other.mTotalSamplingTime; - mMean = (mMean * weight) + (other.mMean * (1.0 - weight)); - } if (append_type == SEQUENTIAL) { mLastValue = other.mLastValue; @@ -234,6 +238,29 @@ void SampleAccumulator::reset( const SampleAccumulator* other ) mTotalSamplingTime = 0; } +F64 EventAccumulator::mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b) +{ + if (a.mNumSamples && b.mNumSamples) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.mNumSamples, + n_2 = b.mNumSamples; + F64 m_1 = a.mMean, + m_2 = b.mMean; + F64 v_1 = a.mSumOfSquares / a.mNumSamples, + v_2 = b.mSumOfSquares / b.mNumSamples; + return (F64)a.mNumSamples + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); + } + + return a.mSumOfSquares; +} + void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendType append_type ) { if (other.mNumSamples) @@ -250,20 +277,7 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT if (other.mMin < mMin) { mMin = other.mMin; } if (other.mMax > mMax) { mMax = other.mMax; } - // combine variance (and hence standard deviation) of 2 different sized sample groups using - // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm - F64 n_1 = (F64)mNumSamples, - n_2 = (F64)other.mNumSamples; - F64 m_1 = mMean, - m_2 = other.mMean; - F64 v_1 = mSumOfSquares / mNumSamples, - v_2 = other.mSumOfSquares / other.mNumSamples; - mSumOfSquares = (F64)mNumSamples - * ((((n_1 - 1.f) * v_1) - + ((n_2 - 1.f) * v_2) - + (((n_1 * n_2) / (n_1 + n_2)) - * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) - / (n_1 + n_2 - 1.f)); + mSumOfSquares = mergeSumsOfSquares(*this, other); F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); mNumSamples += other.mNumSamples; diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index 2971907849..dfa037d7c0 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -276,6 +276,9 @@ namespace LLTrace S32 getSampleCount() const { return mNumSamples; } bool hasValue() const { return mNumSamples > 0; } + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); + private: F64 mSum, mLastValue; @@ -359,10 +362,13 @@ namespace LLTrace F64 getMean() const { return mMean; } F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } F64 getSumOfSquares() const { return mSumOfSquares; } - F64SecondsImplicit getSamplingTime() { return mTotalSamplingTime; } + F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } S32 getSampleCount() const { return mNumSamples; } bool hasValue() const { return mHasValue; } + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); + private: F64 mSum, mLastValue; diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 5ec7ce56b9..0fd0053240 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -32,6 +32,11 @@ #include "lltracethreadrecorder.h" #include "llthread.h" +inline F64 lerp(F64 a, F64 b, F64 u) +{ + return a + ((b - a) * u); +} + namespace LLTrace { @@ -43,7 +48,7 @@ extern MemStatHandle gTraceMemStat; Recording::Recording(EPlayState state) : mElapsedSeconds(0), - mInHandOff(false) + mActiveBuffers(NULL) { claim_alloc(gTraceMemStat, this); mBuffers = new AccumulatorBufferGroup(); @@ -88,13 +93,20 @@ Recording::~Recording() } } +// brings recording to front of recorder stack, with up to date info void Recording::update() { if (isStarted()) { mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); - AccumulatorBufferGroup* buffers = mBuffers.write(); - LLTrace::get_thread_recorder()->bringUpToDate(buffers); + + llassert(mActiveBuffers); + if(!mActiveBuffers->isCurrent()) + { + AccumulatorBufferGroup* buffers = mBuffers.write(); + LLTrace::get_thread_recorder()->deactivate(buffers); + mActiveBuffers = LLTrace::get_thread_recorder()->activate(buffers); + } mSamplingTimer.reset(); } @@ -112,20 +124,19 @@ void Recording::handleStart() { mSamplingTimer.reset(); mBuffers.setStayUnique(true); - LLTrace::get_thread_recorder()->activate(mBuffers.write(), mInHandOff); - mInHandOff = false; + mActiveBuffers = LLTrace::get_thread_recorder()->activate(mBuffers.write()); } void Recording::handleStop() { mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); + mActiveBuffers = NULL; mBuffers.setStayUnique(false); } void Recording::handleSplitTo(Recording& other) { - other.mInHandOff = true; mBuffers.write()->handOffTo(*other.mBuffers.write()); } @@ -139,214 +150,378 @@ void Recording::appendRecording( Recording& other ) bool Recording::hasValue(const StatType& stat) { - return mBuffers->mStackTimers[stat.getIndex()].hasValue(); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64Seconds Recording::getSum(const StatType& stat) { + update(); const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - return F64Seconds((F64)(accumulator.mTotalTimeCounter) - / (F64)LLTrace::BlockTimerStatHandle::countsPerSecond()); + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds((F64)(accumulator.mTotalTimeCounter) + (F64)(active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + / (F64)LLTrace::BlockTimerStatHandle::countsPerSecond(); } F64Seconds Recording::getSum(const StatType& stat) { + update(); const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - return F64Seconds((F64)(accumulator.mSelfTimeCounter) / (F64)LLTrace::BlockTimerStatHandle::countsPerSecond()); + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0) / (F64)LLTrace::BlockTimerStatHandle::countsPerSecond()); } S32 Recording::getSum(const StatType& stat) { - return mBuffers->mStackTimers[stat.getIndex()].mCalls; + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0); } F64Seconds Recording::getPerSec(const StatType& stat) { + update(); const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mTotalTimeCounter) + return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) / ((F64)LLTrace::BlockTimerStatHandle::countsPerSecond() * mElapsedSeconds.value())); } F64Seconds Recording::getPerSec(const StatType& stat) { + update(); const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mSelfTimeCounter) + return F64Seconds((F64)(accumulator.mSelfTimeCounter + (active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / ((F64)LLTrace::BlockTimerStatHandle::countsPerSecond() * mElapsedSeconds.value())); } F32 Recording::getPerSec(const StatType& stat) { - return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds.value(); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value(); } bool Recording::hasValue(const StatType& stat) { - return mBuffers->mMemStats[stat.getIndex()].mSize.hasValue(); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mSize.hasValue() || (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.hasValue() : false); } F64Kilobytes Recording::getMin(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mSize.getMin()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(llmin(accumulator.mSize.getMin(), (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMin() : F32_MAX))); } F64Kilobytes Recording::getMean(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mSize.getMean()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + + if (active_accumulator && active_accumulator->mSize.hasValue()) + { + return F64Bytes(lerp(accumulator.mSize.getMean(), active_accumulator->mSize.getMean(), active_accumulator->mSize.getSampleCount() / (accumulator.mSize.getSampleCount() + active_accumulator->mSize.getSampleCount()))); + } + else + { + return F64Bytes(accumulator.mSize.getMean()); + } } F64Kilobytes Recording::getMax(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mSize.getMax()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN)); } F64Kilobytes Recording::getStandardDeviation(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mSize.getStandardDeviation()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator.mSize, active_accumulator->mSize); + return F64Bytes(sqrtf(sum_of_squares / (accumulator.mSize.getSamplingTime().value() + active_accumulator->mSize.getSamplingTime().value()))); + } + else + { + return F64Bytes(accumulator.mSize.getStandardDeviation()); + } } F64Kilobytes Recording::getLastValue(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mSize.getLastValue()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue()); } bool Recording::hasValue(const StatType& stat) { - return mBuffers->mMemStats[stat.getIndex()].mAllocations.hasValue(); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false); } F64Kilobytes Recording::getSum(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mAllocations.getSum()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)); } F64Kilobytes Recording::getPerSec(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mAllocations.getSum() / mElapsedSeconds.value()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value()); } S32 Recording::getSampleCount(const StatType& stat) { - return mBuffers->mMemStats[stat.getIndex()].mAllocations.getSampleCount(); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0); } bool Recording::hasValue(const StatType& stat) { - return mBuffers->mMemStats[stat.getIndex()].mDeallocations.hasValue(); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false); } F64Kilobytes Recording::getSum(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mDeallocations.getSum()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)); } F64Kilobytes Recording::getPerSec(const StatType& stat) { - return F64Bytes(mBuffers->mMemStats[stat.getIndex()].mDeallocations.getSum() / mElapsedSeconds.value()); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value()); } S32 Recording::getSampleCount(const StatType& stat) { - return mBuffers->mMemStats[stat.getIndex()].mDeallocations.getSampleCount(); + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0); } bool Recording::hasValue(const StatType& stat) { - return mBuffers->mCounts[stat.getIndex()].hasValue(); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); } F64 Recording::getSum(const StatType& stat) { - return mBuffers->mCounts[stat.getIndex()].getSum(); -} - -F64 Recording::getSum( const StatType& stat) -{ - return (F64)mBuffers->mEvents[stat.getIndex()].getSum(); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); } F64 Recording::getPerSec( const StatType& stat ) { - F64 sum = mBuffers->mCounts[stat.getIndex()].getSum(); - return sum / mElapsedSeconds.value(); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); + return sum / mElapsedSeconds.value(); } S32 Recording::getSampleCount( const StatType& stat ) { - return mBuffers->mCounts[stat.getIndex()].getSampleCount(); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); } bool Recording::hasValue(const StatType& stat) { - return mBuffers->mSamples[stat.getIndex()].hasValue(); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64 Recording::getMin( const StatType& stat ) { - return mBuffers->mSamples[stat.getIndex()].getMin(); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); } F64 Recording::getMax( const StatType& stat ) { - return mBuffers->mSamples[stat.getIndex()].getMax(); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); } F64 Recording::getMean( const StatType& stat ) { - return mBuffers->mSamples[stat.getIndex()].getMean(); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + return lerp(accumulator.getMean(), active_accumulator->getMean(), active_accumulator->getSampleCount() / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getMean(); + } } F64 Recording::getStandardDeviation( const StatType& stat ) { - return mBuffers->mSamples[stat.getIndex()].getStandardDeviation(); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSamplingTime() + active_accumulator->getSamplingTime())); + } + else + { + return accumulator.getStandardDeviation(); + } } F64 Recording::getLastValue( const StatType& stat ) { - return mBuffers->mSamples[stat.getIndex()].getLastValue(); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); } S32 Recording::getSampleCount( const StatType& stat ) { - return mBuffers->mSamples[stat.getIndex()].getSampleCount(); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); } bool Recording::hasValue(const StatType& stat) { - return mBuffers->mEvents[stat.getIndex()].hasValue(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); +} + +F64 Recording::getSum( const StatType& stat) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); } F64 Recording::getMin( const StatType& stat ) { - return mBuffers->mEvents[stat.getIndex()].getMin(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); } F64 Recording::getMax( const StatType& stat ) { - return mBuffers->mEvents[stat.getIndex()].getMax(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); } F64 Recording::getMean( const StatType& stat ) { - return mBuffers->mEvents[stat.getIndex()].getMean(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + return lerp(accumulator.getMean(), active_accumulator->getMean(), active_accumulator->getSampleCount() / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getMean(); + } } F64 Recording::getStandardDeviation( const StatType& stat ) { - return mBuffers->mEvents[stat.getIndex()].getStandardDeviation(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = EventAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getStandardDeviation(); + } } F64 Recording::getLastValue( const StatType& stat ) { - return mBuffers->mEvents[stat.getIndex()].getLastValue(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); } S32 Recording::getSampleCount( const StatType& stat ) { - return mBuffers->mEvents[stat.getIndex()].getSampleCount(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); } /////////////////////////////////////////////////////////////////////// diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index b045aafa11..93ac276e33 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -322,7 +322,7 @@ namespace LLTrace LLTimer mSamplingTimer; F64Seconds mElapsedSeconds; LLCopyOnWritePointer mBuffers; - bool mInHandOff; + AccumulatorBufferGroup* mActiveBuffers; }; diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 7b7da5343d..a70e94e4b1 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -131,7 +131,7 @@ TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode( S32 index ) } -void ThreadRecorder::activate( AccumulatorBufferGroup* recording, bool from_handoff ) +AccumulatorBufferGroup* ThreadRecorder::activate( AccumulatorBufferGroup* recording) { ActiveRecording* active_recording = new ActiveRecording(recording); if (!mActiveRecordings.empty()) @@ -144,6 +144,7 @@ void ThreadRecorder::activate( AccumulatorBufferGroup* recording, bool from_hand mActiveRecordings.push_back(active_recording); mActiveRecordings.back()->mPartialRecording.makeCurrent(); + return &active_recording->mPartialRecording; } ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::bringUpToDate( AccumulatorBufferGroup* recording ) diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h index c6afcdac80..d30fa15ea7 100644 --- a/indra/llcommon/lltracethreadrecorder.h +++ b/indra/llcommon/lltracethreadrecorder.h @@ -47,7 +47,7 @@ namespace LLTrace ~ThreadRecorder(); - void activate(AccumulatorBufferGroup* recording, bool from_handoff = false); + AccumulatorBufferGroup* activate(AccumulatorBufferGroup* recording); void deactivate(AccumulatorBufferGroup* recording); active_recording_list_t::iterator bringUpToDate(AccumulatorBufferGroup* recording); diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp index 8ce509699d..0a9d85ad00 100644 --- a/indra/llcommon/tests/lltrace_test.cpp +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -109,8 +109,9 @@ namespace tut at_work.stop(); drink_coffee(1, S32VentiCup(1)); } - after_3pm.stop(); - all_day.stop(); + // don't need to stop recordings to get accurate values out of them + //after_3pm.stop(); + //all_day.stop(); ensure("count stats are counted when recording is active", at_work.getSum(sCupsOfCoffeeConsumed) == 3 -- cgit v1.3