merge with viewer-release
commit
68f9f656cd
|
|
@ -58,6 +58,7 @@ if (WINDOWS)
|
|||
|
||||
add_definitions(
|
||||
/DLL_WINDOWS=1
|
||||
/DNOMINMAX
|
||||
/DDOM_DYNAMIC
|
||||
/DUNICODE
|
||||
/D_UNICODE
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "vorbis/codec.h"
|
||||
#include "vorbis/vorbisfile.h"
|
||||
#include <iterator>
|
||||
|
||||
extern LLAudioEngine *gAudiop;
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
|
||||
class LLAudioStreamManagerFMOD;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "llcharacter.h"
|
||||
#include "llstring.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#define SKEL_HEADER "Linden Skeleton 1.0"
|
||||
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
|
|||
mIKSolver.solve();
|
||||
|
||||
// use blending...
|
||||
F32 slerp_amt = LLCriticalDamp::getInterpolant(TARGET_LAG_HALF_LIFE);
|
||||
F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TARGET_LAG_HALF_LIFE);
|
||||
shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot);
|
||||
elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot);
|
||||
|
||||
|
|
|
|||
|
|
@ -182,8 +182,8 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
|
|||
LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation();
|
||||
LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld;
|
||||
|
||||
F32 head_slerp_amt = LLCriticalDamp::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE);
|
||||
F32 torso_slerp_amt = LLCriticalDamp::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE);
|
||||
F32 head_slerp_amt = LLSmoothInterpolation::getInterpolant(HEAD_LOOKAT_LAG_HALF_LIFE);
|
||||
F32 torso_slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_LOOKAT_LAG_HALF_LIFE);
|
||||
|
||||
LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "linked_lists.h"
|
||||
#include "v3math.h"
|
||||
|
|
|
|||
|
|
@ -1031,11 +1031,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
|||
if (constraint->mSharedData->mChainLength != 0 &&
|
||||
dist_vec_squared(root_pos, target_pos) * 0.95f > constraint->mTotalLength * constraint->mTotalLength)
|
||||
{
|
||||
constraint->mWeight = lerp(constraint->mWeight, 0.f, LLCriticalDamp::getInterpolant(0.1f));
|
||||
constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 0.f, 0.1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
constraint->mWeight = lerp(constraint->mWeight, 1.f, LLCriticalDamp::getInterpolant(0.3f));
|
||||
constraint->mWeight = LLSmoothInterpolation::lerp(constraint->mWeight, 1.f, 0.3f);
|
||||
}
|
||||
|
||||
F32 weight = constraint->mWeight * ((shared_data->mEaseOutStopTime == 0.f) ? 1.f :
|
||||
|
|
@ -1082,9 +1082,9 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
|||
// convert intermediate joint positions to world coordinates
|
||||
positions[joint_num] = ( constraint->mPositions[joint_num] * mPelvisp->getWorldRotation()) + mPelvisp->getWorldPosition();
|
||||
F32 time_constant = 1.f / clamp_rescale(constraint->mFixupDistanceRMS, 0.f, 0.5f, 0.2f, 8.f);
|
||||
// llinfos << "Interpolant " << LLCriticalDamp::getInterpolant(time_constant, FALSE) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl;
|
||||
// llinfos << "Interpolant " << LLSmoothInterpolation::getInterpolant(time_constant, FALSE) << " and fixup distance " << constraint->mFixupDistanceRMS << " on " << mCharacter->findCollisionVolume(shared_data->mSourceConstraintVolume)->getName() << llendl;
|
||||
positions[joint_num] = lerp(positions[joint_num], kinematic_position,
|
||||
LLCriticalDamp::getInterpolant(time_constant, FALSE));
|
||||
LLSmoothInterpolation::getInterpolant(time_constant, FALSE));
|
||||
}
|
||||
|
||||
S32 iteration_count;
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
|||
// but this will cause the animation playback rate calculation below to
|
||||
// kick in too slowly and sometimes start playing the animation in reverse.
|
||||
|
||||
//mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLCriticalDamp::getInterpolant(0.1f));
|
||||
//mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLSmoothInterpolation::getInterpolant(0.1f));
|
||||
|
||||
////F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL * (llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED);
|
||||
//F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL;
|
||||
|
|
@ -287,7 +287,7 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
|||
F32 desired_speed_multiplier = llclamp(speed / foot_speed, min_speed_multiplier, ANIM_SPEED_MAX);
|
||||
|
||||
// blend towards new speed adjustment value
|
||||
F32 new_speed_adjust = lerp(mAdjustedSpeed, desired_speed_multiplier, LLCriticalDamp::getInterpolant(SPEED_ADJUST_TIME_CONSTANT));
|
||||
F32 new_speed_adjust = LLSmoothInterpolation::lerp(mAdjustedSpeed, desired_speed_multiplier, SPEED_ADJUST_TIME_CONSTANT);
|
||||
|
||||
// limit that rate at which the speed adjustment changes
|
||||
F32 speedDelta = llclamp(new_speed_adjust - mAdjustedSpeed, -SPEED_ADJUST_MAX_SEC * delta_time, SPEED_ADJUST_MAX_SEC * delta_time);
|
||||
|
|
@ -305,8 +305,8 @@ BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
|||
{ // standing/turning
|
||||
|
||||
// damp out speed adjustment to 0
|
||||
mAnimSpeed = lerp(mAnimSpeed, 1.f, LLCriticalDamp::getInterpolant(0.2f));
|
||||
//mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLCriticalDamp::getInterpolant(0.2f));
|
||||
mAnimSpeed = LLSmoothInterpolation::lerp(mAnimSpeed, 1.f, 0.2f);
|
||||
//mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLSmoothInterpolation::getInterpolant(0.2f));
|
||||
}
|
||||
|
||||
// broadcast walk speed change
|
||||
|
|
@ -383,7 +383,7 @@ BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
|
|||
F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;
|
||||
|
||||
// roll is critically damped interpolation between current roll and angular velocity-derived target roll
|
||||
mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));
|
||||
mRoll = LLSmoothInterpolation::lerp(mRoll, target_roll, LLUnit<LLUnits::Milliseconds, F32>(100));
|
||||
|
||||
LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
|
||||
mPelvisState->setRotation(roll);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ void LLMotion::fadeOut()
|
|||
{
|
||||
if (mFadeWeight > 0.01f)
|
||||
{
|
||||
mFadeWeight = lerp(mFadeWeight, 0.f, LLCriticalDamp::getInterpolant(0.15f));
|
||||
mFadeWeight = lerp(mFadeWeight, 0.f, LLSmoothInterpolation::getInterpolant(0.15f));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -88,7 +88,7 @@ void LLMotion::fadeIn()
|
|||
{
|
||||
if (mFadeWeight < 0.99f)
|
||||
{
|
||||
mFadeWeight = lerp(mFadeWeight, 1.f, LLCriticalDamp::getInterpolant(0.15f));
|
||||
mFadeWeight = lerp(mFadeWeight, 1.f, LLSmoothInterpolation::getInterpolant(0.15f));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "linden_common.h"
|
||||
|
||||
#include "llmotioncontroller.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llkeyframemotion.h"
|
||||
#include "llmath.h"
|
||||
#include "lltimer.h"
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ BOOL LLTargetingMotion::onActivate()
|
|||
//-----------------------------------------------------------------------------
|
||||
BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask)
|
||||
{
|
||||
F32 slerp_amt = LLCriticalDamp::getInterpolant(TORSO_TARGET_HALF_LIFE);
|
||||
F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE);
|
||||
|
||||
LLVector3 target;
|
||||
LLVector3* lookAtPoint = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");
|
||||
|
|
|
|||
|
|
@ -74,8 +74,10 @@ set(llcommon_SOURCE_FILES
|
|||
llmetrics.cpp
|
||||
llmetricperformancetester.cpp
|
||||
llmortician.cpp
|
||||
llmutex.cpp
|
||||
lloptioninterface.cpp
|
||||
llptrto.cpp
|
||||
llpredicate.cpp
|
||||
llprocess.cpp
|
||||
llprocessor.cpp
|
||||
llqueuedthread.cpp
|
||||
|
|
@ -89,7 +91,6 @@ set(llcommon_SOURCE_FILES
|
|||
llsdutil.cpp
|
||||
llsecondlifeurls.cpp
|
||||
llsingleton.cpp
|
||||
llstat.cpp
|
||||
llstacktrace.cpp
|
||||
llstreamqueue.cpp
|
||||
llstreamtools.cpp
|
||||
|
|
@ -97,8 +98,12 @@ set(llcommon_SOURCE_FILES
|
|||
llstringtable.cpp
|
||||
llsys.cpp
|
||||
llthread.cpp
|
||||
llthreadlocalstorage.cpp
|
||||
llthreadsafequeue.cpp
|
||||
lltimer.cpp
|
||||
lltrace.cpp
|
||||
lltracerecording.cpp
|
||||
lltracethreadrecorder.cpp
|
||||
lluri.cpp
|
||||
lluuid.cpp
|
||||
llworkerthread.cpp
|
||||
|
|
@ -198,9 +203,11 @@ set(llcommon_HEADER_FILES
|
|||
llmetrics.h
|
||||
llmetricperformancetester.h
|
||||
llmortician.h
|
||||
llmutex.h
|
||||
llnametable.h
|
||||
lloptioninterface.h
|
||||
llpointer.h
|
||||
llpredicate.h
|
||||
llpreprocessor.h
|
||||
llpriqueuemap.h
|
||||
llprocess.h
|
||||
|
|
@ -228,7 +235,6 @@ set(llcommon_HEADER_FILES
|
|||
llsortedvector.h
|
||||
llstack.h
|
||||
llstacktrace.h
|
||||
llstat.h
|
||||
llstatenums.h
|
||||
llstl.h
|
||||
llstreamqueue.h
|
||||
|
|
@ -238,15 +244,22 @@ set(llcommon_HEADER_FILES
|
|||
llstringtable.h
|
||||
llsys.h
|
||||
llthread.h
|
||||
llthreadlocalstorage.h
|
||||
llthreadsafequeue.h
|
||||
lltimer.h
|
||||
lltrace.h
|
||||
lltracerecording.h
|
||||
lltracethreadrecorder.h
|
||||
lltreeiterators.h
|
||||
lltypeinfolookup.h
|
||||
llunit.h
|
||||
lluri.h
|
||||
lluuid.h
|
||||
lluuidhashmap.h
|
||||
llversionserver.h
|
||||
llversionviewer.h
|
||||
llwin32headers.h
|
||||
llwin32headerslean.h
|
||||
llworkerthread.h
|
||||
ll_template_cast.h
|
||||
metaclass.h
|
||||
|
|
@ -334,6 +347,7 @@ if (LL_TESTS)
|
|||
LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
|
||||
LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "linden_common.h"
|
||||
#include "llapr.h"
|
||||
#include "apr_dso.h"
|
||||
#include "llthreadlocalstorage.h"
|
||||
|
||||
apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool
|
||||
LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool.
|
||||
|
|
@ -37,12 +38,15 @@ apr_thread_mutex_t *gCallStacksLogMutexp = NULL;
|
|||
|
||||
const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool
|
||||
|
||||
bool gAPRInitialized = false;
|
||||
|
||||
void ll_init_apr()
|
||||
{
|
||||
// Initialize APR and create the global pool
|
||||
apr_initialize();
|
||||
|
||||
if (!gAPRPoolp)
|
||||
{
|
||||
// Initialize APR and create the global pool
|
||||
apr_initialize();
|
||||
apr_pool_create(&gAPRPoolp, NULL);
|
||||
|
||||
// Initialize the logging mutex
|
||||
|
|
@ -52,13 +56,23 @@ void ll_init_apr()
|
|||
|
||||
if(!LLAPRFile::sAPRFilePoolp)
|
||||
{
|
||||
LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
|
||||
LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE);
|
||||
}
|
||||
|
||||
LLThreadLocalPointerBase::initAllThreadLocalStorage();
|
||||
gAPRInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
bool ll_apr_is_initialized()
|
||||
{
|
||||
return gAPRInitialized;
|
||||
}
|
||||
|
||||
void ll_cleanup_apr()
|
||||
{
|
||||
gAPRInitialized = false;
|
||||
|
||||
LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL;
|
||||
|
||||
if (gLogMutexp)
|
||||
|
|
@ -77,6 +91,9 @@ void ll_cleanup_apr()
|
|||
apr_thread_mutex_destroy(gCallStacksLogMutexp);
|
||||
gCallStacksLogMutexp = NULL;
|
||||
}
|
||||
|
||||
LLThreadLocalPointerBase::destroyAllThreadLocalStorage();
|
||||
|
||||
if (gAPRPoolp)
|
||||
{
|
||||
apr_pool_destroy(gAPRPoolp);
|
||||
|
|
@ -84,7 +101,7 @@ void ll_cleanup_apr()
|
|||
}
|
||||
if (LLAPRFile::sAPRFilePoolp)
|
||||
{
|
||||
delete LLAPRFile::sAPRFilePoolp ;
|
||||
delete LLAPRFile::sAPRFilePoolp ;
|
||||
LLAPRFile::sAPRFilePoolp = NULL ;
|
||||
}
|
||||
apr_terminate();
|
||||
|
|
|
|||
|
|
@ -32,14 +32,6 @@
|
|||
#if LL_LINUX || LL_SOLARIS
|
||||
#include <sys/param.h> // Need PATH_MAX in APR headers...
|
||||
#endif
|
||||
#if LL_WINDOWS
|
||||
// Limit Windows API to small and manageable set.
|
||||
// If you get undefined symbols, find the appropriate
|
||||
// Windows header file and include that in your .cpp file.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
|
@ -48,12 +40,26 @@
|
|||
#include "apr_getopt.h"
|
||||
#include "apr_signal.h"
|
||||
#include "apr_atomic.h"
|
||||
|
||||
#include "llstring.h"
|
||||
|
||||
extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
|
||||
struct apr_dso_handle_t;
|
||||
/**
|
||||
* @brief Function which appropriately logs error or remains quiet on
|
||||
* APR_SUCCESS.
|
||||
* @return Returns <code>true</code> if status is an error condition.
|
||||
*/
|
||||
bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
|
||||
/// There's a whole other APR error-message function if you pass a DSO handle.
|
||||
bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle);
|
||||
|
||||
void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
|
||||
void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
|
||||
|
||||
extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
|
||||
|
||||
/**
|
||||
* @brief initialize the common apr constructs -- apr itself, the
|
||||
|
|
@ -66,6 +72,9 @@ void LL_COMMON_API ll_init_apr();
|
|||
*/
|
||||
void LL_COMMON_API ll_cleanup_apr();
|
||||
|
||||
bool LL_COMMON_API ll_apr_is_initialized();
|
||||
|
||||
|
||||
//
|
||||
//LL apr_pool
|
||||
//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
|
||||
|
|
@ -163,14 +172,17 @@ public:
|
|||
LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
|
||||
~LLAtomic32<Type>() {};
|
||||
|
||||
operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
|
||||
operator const Type() { return get(); }
|
||||
Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
|
||||
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
|
||||
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
|
||||
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
|
||||
Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
|
||||
Type operator ++() { apr_atomic_inc32(&mData); return get(); } // ++Type
|
||||
Type operator --(int) { const Type result(get()); apr_atomic_dec32(&mData); return result; } // Type--
|
||||
Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
|
||||
|
||||
private:
|
||||
const Type get() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
|
||||
apr_uint32_t mData;
|
||||
};
|
||||
|
||||
|
|
@ -255,18 +267,5 @@ public:
|
|||
//*******************************************************************************************************************************
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function which appropriately logs error or remains quiet on
|
||||
* APR_SUCCESS.
|
||||
* @return Returns <code>true</code> if status is an error condition.
|
||||
*/
|
||||
bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
|
||||
/// There's a whole other APR error-message function if you pass a DSO handle.
|
||||
bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle);
|
||||
|
||||
void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
|
||||
void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle);
|
||||
|
||||
extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
|
||||
|
||||
#endif // LL_LLAPR_H
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "llmemory.h"
|
||||
#include "llthread.h"
|
||||
#include "lltrace.h"
|
||||
|
||||
//static
|
||||
BOOL LLCommon::sAprInitialized = FALSE;
|
||||
|
|
@ -44,15 +45,13 @@ void LLCommon::initClass()
|
|||
}
|
||||
LLTimer::initClass();
|
||||
LLThreadSafeRefCount::initThreadSafeRefCount();
|
||||
// LLWorkerThread::initClass();
|
||||
// LLFrameCallbackManager::initClass();
|
||||
LLTrace::init();
|
||||
}
|
||||
|
||||
//static
|
||||
void LLCommon::cleanupClass()
|
||||
{
|
||||
// LLFrameCallbackManager::cleanupClass();
|
||||
// LLWorkerThread::cleanupClass();
|
||||
LLTrace::cleanup();
|
||||
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
|
||||
LLTimer::cleanupClass();
|
||||
if (sAprInitialized)
|
||||
|
|
|
|||
|
|
@ -27,18 +27,38 @@
|
|||
#include "linden_common.h"
|
||||
|
||||
#include "llcriticaldamp.h"
|
||||
#include <algorithm>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// static members
|
||||
//-----------------------------------------------------------------------------
|
||||
LLFrameTimer LLCriticalDamp::sInternalTimer;
|
||||
std::map<F32, F32> LLCriticalDamp::sInterpolants;
|
||||
F32 LLCriticalDamp::sTimeDelta;
|
||||
LLFrameTimer LLSmoothInterpolation::sInternalTimer;
|
||||
std::vector<LLSmoothInterpolation::Interpolant> LLSmoothInterpolation::sInterpolants;
|
||||
F32 LLSmoothInterpolation::sTimeDelta;
|
||||
|
||||
// helper functors
|
||||
struct LLSmoothInterpolation::CompareTimeConstants
|
||||
{
|
||||
bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const
|
||||
{
|
||||
return a < b.mTimeScale;
|
||||
}
|
||||
|
||||
bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const
|
||||
{
|
||||
return a.mTimeScale < b; // bottom of a is higher than bottom of b
|
||||
}
|
||||
|
||||
bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const
|
||||
{
|
||||
return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLCriticalDamp()
|
||||
// LLSmoothInterpolation()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLCriticalDamp::LLCriticalDamp()
|
||||
LLSmoothInterpolation::LLSmoothInterpolation()
|
||||
{
|
||||
sTimeDelta = 0.f;
|
||||
}
|
||||
|
|
@ -47,43 +67,54 @@ LLCriticalDamp::LLCriticalDamp()
|
|||
//-----------------------------------------------------------------------------
|
||||
// updateInterpolants()
|
||||
//-----------------------------------------------------------------------------
|
||||
void LLCriticalDamp::updateInterpolants()
|
||||
void LLSmoothInterpolation::updateInterpolants()
|
||||
{
|
||||
sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32();
|
||||
|
||||
F32 time_constant;
|
||||
|
||||
for (std::map<F32, F32>::iterator iter = sInterpolants.begin();
|
||||
iter != sInterpolants.end(); iter++)
|
||||
for (S32 i = 0; i < sInterpolants.size(); i++)
|
||||
{
|
||||
time_constant = iter->first;
|
||||
F32 new_interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant);
|
||||
new_interpolant = llclamp(new_interpolant, 0.f, 1.f);
|
||||
sInterpolants[time_constant] = new_interpolant;
|
||||
Interpolant& interp = sInterpolants[i];
|
||||
interp.mInterpolant = calcInterpolant(interp.mTimeScale);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// getInterpolant()
|
||||
//-----------------------------------------------------------------------------
|
||||
F32 LLCriticalDamp::getInterpolant(const F32 time_constant, BOOL use_cache)
|
||||
F32 LLSmoothInterpolation::getInterpolant(LLUnit<LLUnits::Seconds, F32> time_constant, bool use_cache)
|
||||
{
|
||||
if (time_constant == 0.f)
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
if (use_cache && sInterpolants.count(time_constant))
|
||||
{
|
||||
return sInterpolants[time_constant];
|
||||
}
|
||||
|
||||
F32 interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant);
|
||||
interpolant = llclamp(interpolant, 0.f, 1.f);
|
||||
if (use_cache)
|
||||
{
|
||||
sInterpolants[time_constant] = interpolant;
|
||||
interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants());
|
||||
if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant)
|
||||
{
|
||||
return find_it->mInterpolant;
|
||||
}
|
||||
else
|
||||
{
|
||||
Interpolant interp;
|
||||
interp.mTimeScale = time_constant.value();
|
||||
interp.mInterpolant = calcInterpolant(time_constant.value());
|
||||
sInterpolants.insert(find_it, interp);
|
||||
return interp.mInterpolant;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return calcInterpolant(time_constant.value());
|
||||
|
||||
return interpolant;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// calcInterpolant()
|
||||
//-----------------------------------------------------------------------------
|
||||
F32 LLSmoothInterpolation::calcInterpolant(F32 time_constant)
|
||||
{
|
||||
return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,26 +28,46 @@
|
|||
#ifndef LL_LLCRITICALDAMP_H
|
||||
#define LL_LLCRITICALDAMP_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "llframetimer.h"
|
||||
#include "llunit.h"
|
||||
|
||||
class LL_COMMON_API LLCriticalDamp
|
||||
class LL_COMMON_API LLSmoothInterpolation
|
||||
{
|
||||
public:
|
||||
LLCriticalDamp();
|
||||
LLSmoothInterpolation();
|
||||
|
||||
// MANIPULATORS
|
||||
static void updateInterpolants();
|
||||
|
||||
// ACCESSORS
|
||||
static F32 getInterpolant(const F32 time_constant, BOOL use_cache = TRUE);
|
||||
static F32 getInterpolant(LLUnit<LLUnits::Seconds, F32> time_constant, bool use_cache = true);
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
static T lerp(T a, T b, LLUnit<LLUnits::Seconds, F32> time_constant, bool use_cache = true)
|
||||
{
|
||||
F32 interpolant = getInterpolant(time_constant, use_cache);
|
||||
return ((a * (1.f - interpolant))
|
||||
+ (b * interpolant));
|
||||
}
|
||||
|
||||
protected:
|
||||
static F32 calcInterpolant(F32 time_constant);
|
||||
|
||||
struct CompareTimeConstants;
|
||||
static LLFrameTimer sInternalTimer; // frame timer for calculating deltas
|
||||
|
||||
static std::map<F32, F32> sInterpolants;
|
||||
struct Interpolant
|
||||
{
|
||||
F32 mTimeScale;
|
||||
F32 mInterpolant;
|
||||
};
|
||||
typedef std::vector<Interpolant> interpolant_vec_t;
|
||||
static interpolant_vec_t sInterpolants;
|
||||
static F32 sTimeDelta;
|
||||
};
|
||||
|
||||
typedef LLSmoothInterpolation LLCriticalDamp;
|
||||
|
||||
#endif // LL_LLCRITICALDAMP_H
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "lltimer.h"
|
||||
#include "llstring.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
static const F64 DATE_EPOCH = 0.0;
|
||||
|
||||
|
|
@ -48,18 +49,15 @@ static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
|
|||
|
||||
|
||||
LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
LLDate::LLDate(const LLDate& date) :
|
||||
mSecondsSinceEpoch(date.mSecondsSinceEpoch)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
LLDate::LLDate(F64 seconds_since_epoch) :
|
||||
mSecondsSinceEpoch(seconds_since_epoch)
|
||||
{
|
||||
}
|
||||
LLDate::LLDate(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch) :
|
||||
mSecondsSinceEpoch(seconds_since_epoch.value())
|
||||
{}
|
||||
|
||||
LLDate::LLDate(const std::string& iso8601_date)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llunit.h"
|
||||
|
||||
/**
|
||||
* @class LLDate
|
||||
|
|
@ -56,9 +57,9 @@ public:
|
|||
/**
|
||||
* @brief Construct a date from a seconds since epoch value.
|
||||
*
|
||||
* @pararm seconds_since_epoch The number of seconds since UTC epoch.
|
||||
* @param seconds_since_epoch The number of seconds since UTC epoch.
|
||||
*/
|
||||
LLDate(F64 seconds_since_epoch);
|
||||
LLDate(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch);
|
||||
|
||||
/**
|
||||
* @brief Construct a date from a string representation
|
||||
|
|
|
|||
|
|
@ -244,5 +244,8 @@ inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs)
|
|||
rhs = tmp;
|
||||
}
|
||||
|
||||
#define LL_GLUE_IMPL(x, y) x##y
|
||||
#define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y)
|
||||
|
||||
#endif // LL_LLDEFS_H
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#define LL_LLERRORLEGACY_H
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
/*
|
||||
LEGACY -- DO NOT USE THIS STUFF ANYMORE
|
||||
|
|
@ -111,6 +112,14 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
|
|||
#define llverify(func) do {if (func) {}} while(0)
|
||||
#endif
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
#define llstatic_assert(func, msg) static_assert(func, msg)
|
||||
#define llstatic_assert_template(type, func, msg) static_assert(func, msg)
|
||||
#else
|
||||
#define llstatic_assert(func, msg) BOOST_STATIC_ASSERT(func)
|
||||
#define llstatic_assert_template(type, func, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && func);
|
||||
#endif
|
||||
|
||||
// handy compile-time assert - enforce those template parameters!
|
||||
#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */
|
||||
//XXX: used in two places in llcommon/llskipmap.h
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
#include <algorithm>
|
||||
// std headers
|
||||
#include <typeinfo>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cctype>
|
||||
// external library headers
|
||||
|
|
|
|||
|
|
@ -32,8 +32,13 @@
|
|||
#include "llsingleton.h"
|
||||
#include "lltreeiterators.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llunit.h"
|
||||
#include "llsd.h"
|
||||
#include "lltracerecording.h"
|
||||
#include "lltracethreadrecorder.h"
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <queue>
|
||||
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
|
@ -49,37 +54,36 @@
|
|||
#error "architecture not supported"
|
||||
#endif
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// statics
|
||||
|
||||
S32 LLFastTimer::sCurFrameIndex = -1;
|
||||
S32 LLFastTimer::sLastFrameIndex = -1;
|
||||
U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64();
|
||||
bool LLFastTimer::sPauseHistory = 0;
|
||||
bool LLFastTimer::sResetHistory = 0;
|
||||
LLFastTimer::CurTimerData LLFastTimer::sCurTimerData;
|
||||
BOOL LLFastTimer::sLog = FALSE;
|
||||
std::string LLFastTimer::sLogName = "";
|
||||
BOOL LLFastTimer::sMetricLog = FALSE;
|
||||
LLMutex* LLFastTimer::sLogLock = NULL;
|
||||
std::queue<LLSD> LLFastTimer::sLogQueue;
|
||||
bool TimeBlock::sLog = false;
|
||||
std::string TimeBlock::sLogName = "";
|
||||
bool TimeBlock::sMetricLog = false;
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
|
||||
U64 TimeBlock::sClockResolution = 1000000000; // Nanosecond resolution
|
||||
#else
|
||||
U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
|
||||
U64 TimeBlock::sClockResolution = 1000000; // Microsecond resolution
|
||||
#endif
|
||||
|
||||
static LLMutex* sLogLock = NULL;
|
||||
static std::queue<LLSD> sLogQueue;
|
||||
|
||||
|
||||
// FIXME: move these declarations to the relevant modules
|
||||
|
||||
// helper functions
|
||||
typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t;
|
||||
typedef LLTreeDFSPostIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_bottom_up_iterator_t;
|
||||
|
||||
static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id)
|
||||
static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(TimeBlock& id)
|
||||
{
|
||||
return timer_tree_bottom_up_iterator_t(&id,
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
|
||||
boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1),
|
||||
boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
|
||||
}
|
||||
|
||||
static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
|
||||
|
|
@ -87,14 +91,14 @@ static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
|
|||
return timer_tree_bottom_up_iterator_t();
|
||||
}
|
||||
|
||||
typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t;
|
||||
typedef LLTreeDFSIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_dfs_iterator_t;
|
||||
|
||||
|
||||
static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id)
|
||||
static timer_tree_dfs_iterator_t begin_timer_tree(TimeBlock& id)
|
||||
{
|
||||
return timer_tree_dfs_iterator_t(&id,
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1),
|
||||
boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1));
|
||||
boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1),
|
||||
boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
|
||||
}
|
||||
|
||||
static timer_tree_dfs_iterator_t end_timer_tree()
|
||||
|
|
@ -102,90 +106,48 @@ static timer_tree_dfs_iterator_t end_timer_tree()
|
|||
return timer_tree_dfs_iterator_t();
|
||||
}
|
||||
|
||||
// factory class that creates NamedTimers via static DeclareTimer objects
|
||||
class NamedTimerFactory : public LLSingleton<NamedTimerFactory>
|
||||
|
||||
// sort child timers by name
|
||||
struct SortTimerByName
|
||||
{
|
||||
public:
|
||||
NamedTimerFactory()
|
||||
: mTimerRoot(NULL)
|
||||
{}
|
||||
|
||||
/*virtual */ void initSingleton()
|
||||
bool operator()(const TimeBlock* i1, const TimeBlock* i2)
|
||||
{
|
||||
mTimerRoot = new LLFastTimer::NamedTimer("root");
|
||||
mRootFrameState.setNamedTimer(mTimerRoot);
|
||||
mTimerRoot->setFrameState(&mRootFrameState);
|
||||
mTimerRoot->mParent = mTimerRoot;
|
||||
mTimerRoot->setCollapsed(false);
|
||||
mRootFrameState.mParent = &mRootFrameState;
|
||||
return i1->getName() < i2->getName();
|
||||
}
|
||||
|
||||
~NamedTimerFactory()
|
||||
{
|
||||
std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer());
|
||||
|
||||
delete mTimerRoot;
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer& createNamedTimer(const std::string& name, LLFastTimer::FrameState* state)
|
||||
{
|
||||
LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name);
|
||||
timer->setFrameState(state);
|
||||
timer->setParent(mTimerRoot);
|
||||
mTimers.insert(std::make_pair(name, timer));
|
||||
|
||||
return *timer;
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer* getTimerByName(const std::string& name)
|
||||
{
|
||||
timer_map_t::iterator found_it = mTimers.find(name);
|
||||
if (found_it != mTimers.end())
|
||||
{
|
||||
return found_it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; }
|
||||
|
||||
typedef std::multimap<std::string, LLFastTimer::NamedTimer*> timer_map_t;
|
||||
timer_map_t::iterator beginTimers() { return mTimers.begin(); }
|
||||
timer_map_t::iterator endTimers() { return mTimers.end(); }
|
||||
S32 timerCount() { return mTimers.size(); }
|
||||
|
||||
private:
|
||||
timer_map_t mTimers;
|
||||
|
||||
LLFastTimer::NamedTimer* mTimerRoot;
|
||||
LLFastTimer::FrameState mRootFrameState;
|
||||
};
|
||||
|
||||
LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open )
|
||||
: mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState))
|
||||
TimeBlock& TimeBlock::getRootTimeBlock()
|
||||
{
|
||||
static TimeBlock root_timer("root", true, NULL);
|
||||
return root_timer;
|
||||
}
|
||||
|
||||
void TimeBlock::pushLog(LLSD log)
|
||||
{
|
||||
LLMutexLock lock(sLogLock);
|
||||
|
||||
sLogQueue.push(log);
|
||||
}
|
||||
|
||||
void TimeBlock::setLogLock(LLMutex* lock)
|
||||
{
|
||||
mTimer.setCollapsed(!open);
|
||||
sLogLock = lock;
|
||||
}
|
||||
|
||||
LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
|
||||
: mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState))
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
U64 TimeBlock::countsPerSecond()
|
||||
{
|
||||
return sClockResolution >> 8;
|
||||
return sClockResolution;
|
||||
}
|
||||
#else // windows or x86-mac or x86-linux or x86-solaris
|
||||
U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
||||
U64 TimeBlock::countsPerSecond()
|
||||
{
|
||||
#if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS
|
||||
//getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz
|
||||
static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0);
|
||||
static LLUnit<LLUnits::Hertz, U64> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency();
|
||||
|
||||
// we drop the low-order byte in our timers, so report a lower frequency
|
||||
#else
|
||||
// If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
|
||||
// Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
|
||||
|
|
@ -198,269 +160,185 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
|
|||
firstcall = false;
|
||||
}
|
||||
#endif
|
||||
return sCPUClockFrequency >> 8;
|
||||
return sCPUClockFrequency.value();
|
||||
}
|
||||
#endif
|
||||
|
||||
LLFastTimer::FrameState::FrameState()
|
||||
: mActiveCount(0),
|
||||
mCalls(0),
|
||||
mSelfTimeCounter(0),
|
||||
mParent(NULL),
|
||||
mLastCaller(NULL),
|
||||
mMoveUpTree(false)
|
||||
{}
|
||||
|
||||
|
||||
LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
|
||||
: mName(name),
|
||||
mCollapsed(true),
|
||||
mParent(NULL),
|
||||
mTotalTimeCounter(0),
|
||||
mCountAverage(0),
|
||||
mCallAverage(0),
|
||||
mNeedsSorting(false),
|
||||
mFrameState(NULL)
|
||||
TimeBlock::TimeBlock(const char* name, bool open, TimeBlock* parent)
|
||||
: TraceType<TimeBlockAccumulator>(name),
|
||||
mCollapsed(true)
|
||||
{
|
||||
mCountHistory = new U32[HISTORY_NUM];
|
||||
memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
mCallHistory = new U32[HISTORY_NUM];
|
||||
memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
setCollapsed(!open);
|
||||
}
|
||||
|
||||
LLFastTimer::NamedTimer::~NamedTimer()
|
||||
TimeBlockTreeNode& TimeBlock::getTreeNode() const
|
||||
{
|
||||
delete[] mCountHistory;
|
||||
delete[] mCallHistory;
|
||||
}
|
||||
|
||||
std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
|
||||
{
|
||||
F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond();
|
||||
if (history_idx < 0)
|
||||
{
|
||||
// by default, show average number of call
|
||||
return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getCountAverage() * ms_multiplier), (S32)getCallAverage());
|
||||
TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex());
|
||||
llassert(nodep);
|
||||
return *nodep;
|
||||
}
|
||||
else
|
||||
{
|
||||
return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx));
|
||||
}
|
||||
}
|
||||
|
||||
void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
|
||||
{
|
||||
llassert_always(parent != this);
|
||||
llassert_always(parent != NULL);
|
||||
|
||||
if (mParent)
|
||||
{
|
||||
// subtract our accumulated from previous parent
|
||||
for (S32 i = 0; i < HISTORY_NUM; i++)
|
||||
{
|
||||
mParent->mCountHistory[i] -= mCountHistory[i];
|
||||
}
|
||||
|
||||
// subtract average timing from previous parent
|
||||
mParent->mCountAverage -= mCountAverage;
|
||||
|
||||
std::vector<NamedTimer*>& children = mParent->getChildren();
|
||||
std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
|
||||
if (found_it != children.end())
|
||||
{
|
||||
children.erase(found_it);
|
||||
}
|
||||
}
|
||||
|
||||
mParent = parent;
|
||||
if (parent)
|
||||
{
|
||||
getFrameState().mParent = &parent->getFrameState();
|
||||
parent->getChildren().push_back(this);
|
||||
parent->mNeedsSorting = true;
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLFastTimer::NamedTimer::getDepth()
|
||||
{
|
||||
S32 depth = 0;
|
||||
NamedTimer* timerp = mParent;
|
||||
while(timerp)
|
||||
{
|
||||
depth++;
|
||||
if (timerp->getParent() == timerp) break;
|
||||
timerp = timerp->mParent;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFastTimer::NamedTimer::processTimes()
|
||||
{
|
||||
if (sCurFrameIndex < 0) return;
|
||||
|
||||
buildHierarchy();
|
||||
accumulateTimings();
|
||||
}
|
||||
|
||||
// sort child timers by name
|
||||
struct SortTimerByName
|
||||
{
|
||||
bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2)
|
||||
{
|
||||
return i1->getName() < i2->getName();
|
||||
}
|
||||
};
|
||||
|
||||
//static
|
||||
void LLFastTimer::NamedTimer::buildHierarchy()
|
||||
void TimeBlock::processTimes()
|
||||
{
|
||||
if (sCurFrameIndex < 0 ) return;
|
||||
get_clock_count(); // good place to calculate clock frequency
|
||||
U64 cur_time = getCPUClockCount64();
|
||||
|
||||
// set up initial tree
|
||||
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
if (&timer == NamedTimerFactory::instance().getRootTimer()) continue;
|
||||
TimeBlock& timer = *it;
|
||||
if (&timer == &TimeBlock::getRootTimeBlock()) continue;
|
||||
|
||||
// bootstrap tree construction by attaching to last timer to be on stack
|
||||
// when this timer was called
|
||||
if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer())
|
||||
if (timer.getParent() == &TimeBlock::getRootTimeBlock())
|
||||
{
|
||||
TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
|
||||
|
||||
if (accumulator->mLastCaller)
|
||||
{
|
||||
timer.setParent(timer.getFrameState().mLastCaller->mTimer);
|
||||
// no need to push up tree on first use, flag can be set spuriously
|
||||
timer.getFrameState().mMoveUpTree = false;
|
||||
timer.setParent(accumulator->mLastCaller);
|
||||
accumulator->mParent = accumulator->mLastCaller;
|
||||
}
|
||||
// no need to push up tree on first use, flag can be set spuriously
|
||||
accumulator->mMoveUpTree = false;
|
||||
}
|
||||
}
|
||||
|
||||
// bump timers up tree if they've been flagged as being in the wrong place
|
||||
// bump timers up tree if they have been flagged as being in the wrong place
|
||||
// do this in a bottom up order to promote descendants first before promoting ancestors
|
||||
// this preserves partial order derived from current frame's observations
|
||||
for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer());
|
||||
for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimeBlock());
|
||||
it != end_timer_tree_bottom_up();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = *it;
|
||||
// skip root timer
|
||||
if (timerp == NamedTimerFactory::instance().getRootTimer()) continue;
|
||||
TimeBlock* timerp = *it;
|
||||
|
||||
if (timerp->getFrameState().mMoveUpTree)
|
||||
// sort timers by time last called, so call graph makes sense
|
||||
TimeBlockTreeNode& tree_node = timerp->getTreeNode();
|
||||
if (tree_node.mNeedsSorting)
|
||||
{
|
||||
// since ancestors have already been visited, reparenting won't affect tree traversal
|
||||
std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName());
|
||||
}
|
||||
|
||||
// skip root timer
|
||||
if (timerp != &TimeBlock::getRootTimeBlock())
|
||||
{
|
||||
TimeBlockAccumulator* accumulator = timerp->getPrimaryAccumulator();
|
||||
|
||||
if (accumulator->mMoveUpTree)
|
||||
{
|
||||
// since ancestors have already been visited, re-parenting won't affect tree traversal
|
||||
//step up tree, bringing our descendants with us
|
||||
LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
|
||||
" to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL;
|
||||
timerp->setParent(timerp->getParent()->getParent());
|
||||
timerp->getFrameState().mMoveUpTree = false;
|
||||
accumulator->mParent = timerp->getParent();
|
||||
accumulator->mMoveUpTree = false;
|
||||
|
||||
// don't bubble up any ancestors until descendants are done bubbling up
|
||||
// as ancestors may call this timer only on certain paths, so we want to resolve
|
||||
// child-most block locations before their parents
|
||||
it.skipAncestors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort timers by time last called, so call graph makes sense
|
||||
for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
|
||||
it != end_timer_tree();
|
||||
// walk up stack of active timers and accumulate current time while leaving timing structures active
|
||||
BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();
|
||||
BlockTimer* cur_timer = stack_record->mActiveTimer;
|
||||
TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
|
||||
|
||||
// root defined by parent pointing to self
|
||||
while(cur_timer && cur_timer->mParentTimerData.mActiveTimer != cur_timer)
|
||||
{
|
||||
U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
|
||||
accumulator->mTotalTimeCounter += cumulative_time_delta - (accumulator->mTotalTimeCounter - cur_timer->mBlockStartTotalTimeCounter);
|
||||
accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime;
|
||||
stack_record->mChildTime = 0;
|
||||
|
||||
cur_timer->mStartTime = cur_time;
|
||||
cur_timer->mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;
|
||||
|
||||
stack_record = &cur_timer->mParentTimerData;
|
||||
accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
|
||||
cur_timer = stack_record->mActiveTimer;
|
||||
|
||||
stack_record->mChildTime += cumulative_time_delta;
|
||||
}
|
||||
|
||||
// reset for next frame
|
||||
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
|
||||
end_it = LLInstanceTracker<TimeBlock>::endInstances();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = (*it);
|
||||
if (timerp->mNeedsSorting)
|
||||
{
|
||||
std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
|
||||
}
|
||||
timerp->mNeedsSorting = false;
|
||||
TimeBlock& timer = *it;
|
||||
TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
|
||||
|
||||
accumulator->mLastCaller = NULL;
|
||||
accumulator->mMoveUpTree = false;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::NamedTimer::accumulateTimings()
|
||||
|
||||
std::vector<TimeBlock*>::iterator TimeBlock::beginChildren()
|
||||
{
|
||||
return getTreeNode().mChildren.begin();
|
||||
}
|
||||
|
||||
std::vector<TimeBlock*>::iterator TimeBlock::endChildren()
|
||||
{
|
||||
return getTreeNode().mChildren.end();
|
||||
}
|
||||
|
||||
std::vector<TimeBlock*>& TimeBlock::getChildren()
|
||||
{
|
||||
U32 cur_time = getCPUClockCount32();
|
||||
|
||||
// walk up stack of active timers and accumulate current time while leaving timing structures active
|
||||
LLFastTimer* cur_timer = sCurTimerData.mCurTimer;
|
||||
// root defined by parent pointing to self
|
||||
CurTimerData* cur_data = &sCurTimerData;
|
||||
while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer)
|
||||
{
|
||||
U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
|
||||
U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
|
||||
cur_data->mChildTime = 0;
|
||||
cur_timer->mFrameState->mSelfTimeCounter += self_time_delta;
|
||||
cur_timer->mStartTime = cur_time;
|
||||
|
||||
cur_data = &cur_timer->mLastTimerData;
|
||||
cur_data->mChildTime += cumulative_time_delta;
|
||||
|
||||
cur_timer = cur_timer->mLastTimerData.mCurTimer;
|
||||
}
|
||||
|
||||
// traverse tree in DFS post order, or bottom up
|
||||
for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer());
|
||||
it != end_timer_tree_bottom_up();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = (*it);
|
||||
timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter;
|
||||
for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
|
||||
{
|
||||
timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter;
|
||||
}
|
||||
|
||||
S32 cur_frame = sCurFrameIndex;
|
||||
if (cur_frame >= 0)
|
||||
{
|
||||
// update timer history
|
||||
int hidx = cur_frame % HISTORY_NUM;
|
||||
|
||||
timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter;
|
||||
timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
|
||||
timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
|
||||
timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
|
||||
}
|
||||
}
|
||||
return getTreeNode().mChildren;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFastTimer::NamedTimer::resetFrame()
|
||||
void TimeBlock::logStats()
|
||||
{
|
||||
// get ready for next frame
|
||||
if (sLog)
|
||||
{ //output current frame counts to performance log
|
||||
|
||||
static S32 call_count = 0;
|
||||
if (call_count % 100 == 0)
|
||||
{
|
||||
LL_DEBUGS("FastTimers") << "countsPerSecond (32 bit): " << countsPerSecond() << LL_ENDL;
|
||||
LL_DEBUGS("FastTimers") << "get_clock_count (64 bit): " << get_clock_count() << llendl;
|
||||
LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL;
|
||||
LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL;
|
||||
LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL;
|
||||
LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL;
|
||||
LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << LL_ENDL;
|
||||
LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64()) / (LLUnit<LLUnits::Hertz, F64>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;
|
||||
}
|
||||
call_count++;
|
||||
|
||||
F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
|
||||
|
||||
F64 total_time = 0;
|
||||
LLUnit<LLUnits::Seconds, F64> total_time(0);
|
||||
LLSD sd;
|
||||
|
||||
{
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
|
||||
end_it = LLInstanceTracker<TimeBlock>::endInstances();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
FrameState& info = timer.getFrameState();
|
||||
sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq);
|
||||
sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls;
|
||||
TimeBlock& timer = *it;
|
||||
LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
|
||||
sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecordingPeriod().getSum(timer).value());
|
||||
sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecordingPeriod().getSum(timer.callCount()));
|
||||
|
||||
// computing total time here because getting the root timer's getCountHistory
|
||||
// doesn't work correctly on the first frame
|
||||
total_time = total_time + info.mSelfTimeCounter * iclock_freq;
|
||||
total_time += frame_recording.getLastRecordingPeriod().getSum(timer);
|
||||
}
|
||||
}
|
||||
|
||||
sd["Total"]["Time"] = (LLSD::Real) total_time;
|
||||
sd["Total"]["Time"] = (LLSD::Real) total_time.value();
|
||||
sd["Total"]["Calls"] = (LLSD::Integer) 1;
|
||||
|
||||
{
|
||||
|
|
@ -469,162 +347,44 @@ void LLFastTimer::NamedTimer::resetFrame()
|
|||
}
|
||||
}
|
||||
|
||||
// reset for next frame
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
|
||||
FrameState& info = timer.getFrameState();
|
||||
info.mSelfTimeCounter = 0;
|
||||
info.mCalls = 0;
|
||||
info.mLastCaller = NULL;
|
||||
info.mMoveUpTree = false;
|
||||
// update parent pointer in timer state struct
|
||||
if (timer.mParent)
|
||||
{
|
||||
info.mParent = &timer.mParent->getFrameState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::NamedTimer::reset()
|
||||
void TimeBlock::dumpCurTimes()
|
||||
{
|
||||
resetFrame(); // reset frame data
|
||||
|
||||
// walk up stack of active timers and reset start times to current time
|
||||
// effectively zeroing out any accumulated time
|
||||
U32 cur_time = getCPUClockCount32();
|
||||
|
||||
// root defined by parent pointing to self
|
||||
CurTimerData* cur_data = &sCurTimerData;
|
||||
LLFastTimer* cur_timer = cur_data->mCurTimer;
|
||||
while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer)
|
||||
{
|
||||
cur_timer->mStartTime = cur_time;
|
||||
cur_data->mChildTime = 0;
|
||||
|
||||
cur_data = &cur_timer->mLastTimerData;
|
||||
cur_timer = cur_data->mCurTimer;
|
||||
}
|
||||
|
||||
// reset all history
|
||||
{
|
||||
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
|
||||
{
|
||||
NamedTimer& timer = *it;
|
||||
if (&timer != NamedTimerFactory::instance().getRootTimer())
|
||||
{
|
||||
timer.setParent(NamedTimerFactory::instance().getRootTimer());
|
||||
}
|
||||
|
||||
timer.mCountAverage = 0;
|
||||
timer.mCallAverage = 0;
|
||||
memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
|
||||
}
|
||||
}
|
||||
|
||||
sLastFrameIndex = 0;
|
||||
sCurFrameIndex = 0;
|
||||
}
|
||||
|
||||
U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const
|
||||
{
|
||||
S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
|
||||
return mCountHistory[history_idx];
|
||||
}
|
||||
|
||||
U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const
|
||||
{
|
||||
S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM;
|
||||
return mCallHistory[history_idx];
|
||||
}
|
||||
|
||||
LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const
|
||||
{
|
||||
return *mFrameState;
|
||||
}
|
||||
|
||||
std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren()
|
||||
{
|
||||
return mChildren.begin();
|
||||
}
|
||||
|
||||
std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren()
|
||||
{
|
||||
return mChildren.end();
|
||||
}
|
||||
|
||||
std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
|
||||
{
|
||||
return mChildren;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::nextFrame()
|
||||
{
|
||||
countsPerSecond(); // good place to calculate clock frequency
|
||||
U64 frame_time = getCPUClockCount64();
|
||||
if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff)
|
||||
{
|
||||
llinfos << "Slow frame, fast timers inaccurate" << llendl;
|
||||
}
|
||||
|
||||
if (!sPauseHistory)
|
||||
{
|
||||
NamedTimer::processTimes();
|
||||
sLastFrameIndex = sCurFrameIndex++;
|
||||
}
|
||||
|
||||
// get ready for next frame
|
||||
NamedTimer::resetFrame();
|
||||
sLastFrameTime = frame_time;
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::dumpCurTimes()
|
||||
{
|
||||
// accumulate timings, etc.
|
||||
NamedTimer::processTimes();
|
||||
|
||||
F64 clock_freq = (F64)countsPerSecond();
|
||||
F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds
|
||||
LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording();
|
||||
LLTrace::Recording& last_frame_recording = frame_recording.getLastRecordingPeriod();
|
||||
|
||||
// walk over timers in depth order and output timings
|
||||
for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
|
||||
for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimeBlock());
|
||||
it != end_timer_tree();
|
||||
++it)
|
||||
{
|
||||
NamedTimer* timerp = (*it);
|
||||
F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
|
||||
TimeBlock* timerp = (*it);
|
||||
LLUnit<LLUnits::Seconds, F64> total_time_ms = last_frame_recording.getSum(*timerp);
|
||||
U32 num_calls = last_frame_recording.getSum(timerp->callCount());
|
||||
|
||||
// Don't bother with really brief times, keep output concise
|
||||
if (total_time_ms < 0.1) continue;
|
||||
|
||||
std::ostringstream out_str;
|
||||
for (S32 i = 0; i < timerp->getDepth(); i++)
|
||||
TimeBlock* parent_timerp = timerp;
|
||||
while(parent_timerp && parent_timerp != parent_timerp->getParent())
|
||||
{
|
||||
out_str << "\t";
|
||||
parent_timerp = parent_timerp->getParent();
|
||||
}
|
||||
|
||||
|
||||
out_str << timerp->getName() << " "
|
||||
<< std::setprecision(3) << total_time_ms << " ms, "
|
||||
<< timerp->getHistoricalCalls(0) << " calls";
|
||||
<< std::setprecision(3) << total_time_ms.as<LLUnits::Milliseconds>().value() << " ms, "
|
||||
<< num_calls << " calls";
|
||||
|
||||
llinfos << out_str.str() << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLFastTimer::reset()
|
||||
{
|
||||
NamedTimer::reset();
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
void LLFastTimer::writeLog(std::ostream& os)
|
||||
void TimeBlock::writeLog(std::ostream& os)
|
||||
{
|
||||
while (!sLogQueue.empty())
|
||||
{
|
||||
|
|
@ -635,22 +395,59 @@ void LLFastTimer::writeLog(std::ostream& os)
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TimeBlockAccumulator
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TimeBlockAccumulator::TimeBlockAccumulator()
|
||||
: mTotalTimeCounter(0),
|
||||
mSelfTimeCounter(0),
|
||||
mStartTotalTimeCounter(0),
|
||||
mCalls(0),
|
||||
mLastCaller(NULL),
|
||||
mActiveCount(0),
|
||||
mMoveUpTree(false),
|
||||
mParent(NULL)
|
||||
{}
|
||||
|
||||
void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other )
|
||||
{
|
||||
return NamedTimerFactory::instance().getTimerByName(name);
|
||||
mTotalTimeCounter += other.mTotalTimeCounter - other.mStartTotalTimeCounter;
|
||||
mSelfTimeCounter += other.mSelfTimeCounter;
|
||||
mCalls += other.mCalls;
|
||||
mLastCaller = other.mLastCaller;
|
||||
mActiveCount = other.mActiveCount;
|
||||
mMoveUpTree = other.mMoveUpTree;
|
||||
mParent = other.mParent;
|
||||
}
|
||||
|
||||
LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
|
||||
: mFrameState(state)
|
||||
void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other )
|
||||
{
|
||||
U32 start_time = getCPUClockCount32();
|
||||
mStartTime = start_time;
|
||||
mFrameState->mActiveCount++;
|
||||
LLFastTimer::sCurTimerData.mCurTimer = this;
|
||||
LLFastTimer::sCurTimerData.mFrameState = mFrameState;
|
||||
LLFastTimer::sCurTimerData.mChildTime = 0;
|
||||
mLastTimerData = LLFastTimer::sCurTimerData;
|
||||
mCalls = 0;
|
||||
mSelfTimeCounter = 0;
|
||||
|
||||
if (other)
|
||||
{
|
||||
mStartTotalTimeCounter = other->mTotalTimeCounter;
|
||||
mTotalTimeCounter = mStartTotalTimeCounter;
|
||||
|
||||
mLastCaller = other->mLastCaller;
|
||||
mActiveCount = other->mActiveCount;
|
||||
mMoveUpTree = other->mMoveUpTree;
|
||||
mParent = other->mParent;
|
||||
}
|
||||
else
|
||||
{
|
||||
mStartTotalTimeCounter = mTotalTimeCounter;
|
||||
}
|
||||
}
|
||||
|
||||
LLUnit<LLUnits::Seconds, F64> BlockTimer::getElapsedTime()
|
||||
{
|
||||
U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
|
||||
|
||||
return (F64)total_time / (F64)TimeBlock::countsPerSecond();
|
||||
}
|
||||
|
||||
|
||||
} // namespace LLTrace
|
||||
|
|
|
|||
|
|
@ -28,214 +28,98 @@
|
|||
#define LL_FASTTIMER_H
|
||||
|
||||
#include "llinstancetracker.h"
|
||||
#include "lltrace.h"
|
||||
|
||||
#define FAST_TIMER_ON 1
|
||||
#define DEBUG_FAST_TIMER_THREADS 1
|
||||
#define LL_FASTTIMER_USE_RDTSC 1
|
||||
|
||||
class LLMutex;
|
||||
|
||||
#include <queue>
|
||||
#include "llsd.h"
|
||||
namespace LLTrace
|
||||
{
|
||||
|
||||
#define LL_FASTTIMER_USE_RDTSC 1
|
||||
struct BlockTimerStackRecord
|
||||
{
|
||||
class BlockTimer* mActiveTimer;
|
||||
class TimeBlock* mTimeBlock;
|
||||
U64 mChildTime;
|
||||
};
|
||||
|
||||
class ThreadTimerStack
|
||||
: public BlockTimerStackRecord,
|
||||
public LLThreadLocalSingleton<ThreadTimerStack>
|
||||
{
|
||||
friend class LLThreadLocalSingleton<ThreadTimerStack>;
|
||||
ThreadTimerStack()
|
||||
{}
|
||||
|
||||
LL_COMMON_API void assert_main_thread();
|
||||
public:
|
||||
ThreadTimerStack& operator=(const BlockTimerStackRecord& other)
|
||||
{
|
||||
BlockTimerStackRecord::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLFastTimer
|
||||
class BlockTimer
|
||||
{
|
||||
public:
|
||||
class NamedTimer;
|
||||
friend class TimeBlock;
|
||||
typedef BlockTimer self_t;
|
||||
typedef class TimeBlock DeclareTimer;
|
||||
|
||||
struct LL_COMMON_API FrameState
|
||||
{
|
||||
FrameState();
|
||||
void setNamedTimer(NamedTimer* timerp) { mTimer = timerp; }
|
||||
BlockTimer(TimeBlock& timer);
|
||||
~BlockTimer();
|
||||
|
||||
U32 mSelfTimeCounter;
|
||||
U32 mCalls;
|
||||
FrameState* mParent; // info for caller timer
|
||||
FrameState* mLastCaller; // used to bootstrap tree construction
|
||||
NamedTimer* mTimer;
|
||||
U16 mActiveCount; // number of timers with this ID active on stack
|
||||
bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
|
||||
};
|
||||
LLUnit<LLUnits::Seconds, F64> getElapsedTime();
|
||||
|
||||
// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
|
||||
class LL_COMMON_API NamedTimer
|
||||
: public LLInstanceTracker<NamedTimer>
|
||||
{
|
||||
friend class DeclareTimer;
|
||||
public:
|
||||
~NamedTimer();
|
||||
private:
|
||||
|
||||
enum { HISTORY_NUM = 300 };
|
||||
|
||||
const std::string& getName() const { return mName; }
|
||||
NamedTimer* getParent() const { return mParent; }
|
||||
void setParent(NamedTimer* parent);
|
||||
S32 getDepth();
|
||||
std::string getToolTip(S32 history_index = -1);
|
||||
|
||||
typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
|
||||
child_const_iter beginChildren();
|
||||
child_const_iter endChildren();
|
||||
std::vector<NamedTimer*>& getChildren();
|
||||
|
||||
void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
|
||||
bool getCollapsed() const { return mCollapsed; }
|
||||
|
||||
U32 getCountAverage() const { return mCountAverage; }
|
||||
U32 getCallAverage() const { return mCallAverage; }
|
||||
|
||||
U32 getHistoricalCount(S32 history_index = 0) const;
|
||||
U32 getHistoricalCalls(S32 history_index = 0) const;
|
||||
|
||||
void setFrameState(FrameState* state) { mFrameState = state; state->setNamedTimer(this); }
|
||||
FrameState& getFrameState() const;
|
||||
|
||||
private:
|
||||
friend class LLFastTimer;
|
||||
friend class NamedTimerFactory;
|
||||
|
||||
//
|
||||
// methods
|
||||
//
|
||||
NamedTimer(const std::string& name);
|
||||
// recursive call to gather total time from children
|
||||
static void accumulateTimings();
|
||||
|
||||
// updates cumulative times and hierarchy,
|
||||
// can be called multiple times in a frame, at any point
|
||||
static void processTimes();
|
||||
|
||||
static void buildHierarchy();
|
||||
static void resetFrame();
|
||||
static void reset();
|
||||
|
||||
//
|
||||
// members
|
||||
//
|
||||
FrameState* mFrameState;
|
||||
|
||||
std::string mName;
|
||||
|
||||
U32 mTotalTimeCounter;
|
||||
|
||||
U32 mCountAverage;
|
||||
U32 mCallAverage;
|
||||
|
||||
U32* mCountHistory;
|
||||
U32* mCallHistory;
|
||||
|
||||
// tree structure
|
||||
NamedTimer* mParent; // NamedTimer of caller(parent)
|
||||
std::vector<NamedTimer*> mChildren;
|
||||
bool mCollapsed; // don't show children
|
||||
bool mNeedsSorting; // sort children whenever child added
|
||||
};
|
||||
|
||||
// used to statically declare a new named timer
|
||||
class LL_COMMON_API DeclareTimer
|
||||
: public LLInstanceTracker<DeclareTimer>
|
||||
{
|
||||
friend class LLFastTimer;
|
||||
public:
|
||||
DeclareTimer(const std::string& name, bool open);
|
||||
DeclareTimer(const std::string& name);
|
||||
|
||||
NamedTimer& getNamedTimer() { return mTimer; }
|
||||
|
||||
private:
|
||||
FrameState mFrameState;
|
||||
NamedTimer& mTimer;
|
||||
};
|
||||
U64 mStartTime;
|
||||
U64 mBlockStartTotalTimeCounter;
|
||||
BlockTimerStackRecord mParentTimerData;
|
||||
};
|
||||
|
||||
// stores a "named" timer instance to be reused via multiple BlockTimer stack instances
|
||||
class TimeBlock
|
||||
: public TraceType<TimeBlockAccumulator>,
|
||||
public LLInstanceTracker<TimeBlock>
|
||||
{
|
||||
public:
|
||||
LLFastTimer(LLFastTimer::FrameState* state);
|
||||
TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimeBlock());
|
||||
|
||||
LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
|
||||
: mFrameState(&timer.mFrameState)
|
||||
{
|
||||
#if FAST_TIMER_ON
|
||||
LLFastTimer::FrameState* frame_state = mFrameState;
|
||||
mStartTime = getCPUClockCount32();
|
||||
TimeBlockTreeNode& getTreeNode() const;
|
||||
TimeBlock* getParent() const { return getTreeNode().getParent(); }
|
||||
void setParent(TimeBlock* parent) { getTreeNode().setParent(parent); }
|
||||
|
||||
frame_state->mActiveCount++;
|
||||
frame_state->mCalls++;
|
||||
// keep current parent as long as it is active when we are
|
||||
frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
|
||||
typedef std::vector<TimeBlock*>::iterator child_iter;
|
||||
typedef std::vector<TimeBlock*>::const_iterator child_const_iter;
|
||||
child_iter beginChildren();
|
||||
child_iter endChildren();
|
||||
std::vector<TimeBlock*>& getChildren();
|
||||
|
||||
LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData;
|
||||
mLastTimerData = *cur_timer_data;
|
||||
cur_timer_data->mCurTimer = this;
|
||||
cur_timer_data->mFrameState = frame_state;
|
||||
cur_timer_data->mChildTime = 0;
|
||||
#endif
|
||||
#if DEBUG_FAST_TIMER_THREADS
|
||||
#if !LL_RELEASE
|
||||
assert_main_thread();
|
||||
#endif
|
||||
#endif
|
||||
void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
|
||||
bool getCollapsed() const { return mCollapsed; }
|
||||
|
||||
TraceType<TimeBlockAccumulator::CallCountAspect>& callCount()
|
||||
{
|
||||
return static_cast<TraceType<TimeBlockAccumulator::CallCountAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE ~LLFastTimer()
|
||||
{
|
||||
#if FAST_TIMER_ON
|
||||
LLFastTimer::FrameState* frame_state = mFrameState;
|
||||
U32 total_time = getCPUClockCount32() - mStartTime;
|
||||
|
||||
frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime;
|
||||
frame_state->mActiveCount--;
|
||||
|
||||
// store last caller to bootstrap tree creation
|
||||
// do this in the destructor in case of recursion to get topmost caller
|
||||
frame_state->mLastCaller = mLastTimerData.mFrameState;
|
||||
|
||||
// we are only tracking self time, so subtract our total time delta from parents
|
||||
mLastTimerData.mChildTime += total_time;
|
||||
|
||||
LLFastTimer::sCurTimerData = mLastTimerData;
|
||||
#endif
|
||||
TraceType<TimeBlockAccumulator::SelfTimeAspect>& selfTime()
|
||||
{
|
||||
return static_cast<TraceType<TimeBlockAccumulator::SelfTimeAspect>&>(*(TraceType<TimeBlockAccumulator>*)this);
|
||||
}
|
||||
|
||||
public:
|
||||
static LLMutex* sLogLock;
|
||||
static std::queue<LLSD> sLogQueue;
|
||||
static BOOL sLog;
|
||||
static BOOL sMetricLog;
|
||||
static std::string sLogName;
|
||||
static bool sPauseHistory;
|
||||
static bool sResetHistory;
|
||||
|
||||
// call this once a frame to reset timers
|
||||
static void nextFrame();
|
||||
static TimeBlock& getRootTimeBlock();
|
||||
static void pushLog(LLSD sd);
|
||||
static void setLogLock(LLMutex* mutex);
|
||||
static void writeLog(std::ostream& os);
|
||||
|
||||
// dumps current cumulative frame stats to log
|
||||
// call nextFrame() to reset timers
|
||||
static void dumpCurTimes();
|
||||
|
||||
// call this to reset timer hierarchy, averages, etc.
|
||||
static void reset();
|
||||
|
||||
static U64 countsPerSecond();
|
||||
static S32 getLastFrameIndex() { return sLastFrameIndex; }
|
||||
static S32 getCurFrameIndex() { return sCurFrameIndex; }
|
||||
|
||||
static void writeLog(std::ostream& os);
|
||||
static const NamedTimer* getTimerByName(const std::string& name);
|
||||
|
||||
struct CurTimerData
|
||||
{
|
||||
LLFastTimer* mCurTimer;
|
||||
FrameState* mFrameState;
|
||||
U32 mChildTime;
|
||||
};
|
||||
static CurTimerData sCurTimerData;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Important note: These implementations must be FAST!
|
||||
|
|
@ -258,14 +142,14 @@ private:
|
|||
//#undef _interlockedbittestandset
|
||||
//#undef _interlockedbittestandreset
|
||||
|
||||
//inline U32 LLFastTimer::getCPUClockCount32()
|
||||
//inline U32 TimeBlock::getCPUClockCount32()
|
||||
//{
|
||||
// U64 time_stamp = __rdtsc();
|
||||
// return (U32)(time_stamp >> 8);
|
||||
//}
|
||||
//
|
||||
//// return full timer value, *not* shifted by 8 bits
|
||||
//inline U64 LLFastTimer::getCPUClockCount64()
|
||||
//inline U64 TimeBlock::getCPUClockCount64()
|
||||
//{
|
||||
// return __rdtsc();
|
||||
//}
|
||||
|
|
@ -305,7 +189,7 @@ private:
|
|||
}
|
||||
|
||||
#else
|
||||
//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
|
||||
//U64 get_clock_count(); // in lltimer.cpp
|
||||
// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
|
||||
static U32 getCPUClockCount32()
|
||||
{
|
||||
|
|
@ -372,18 +256,71 @@ private:
|
|||
|
||||
#endif
|
||||
|
||||
static U64 sClockResolution;
|
||||
static U64 countsPerSecond();
|
||||
|
||||
static S32 sCurFrameIndex;
|
||||
static S32 sLastFrameIndex;
|
||||
static U64 sLastFrameTime;
|
||||
// updates cumulative times and hierarchy,
|
||||
// can be called multiple times in a frame, at any point
|
||||
static void processTimes();
|
||||
|
||||
U32 mStartTime;
|
||||
LLFastTimer::FrameState* mFrameState;
|
||||
LLFastTimer::CurTimerData mLastTimerData;
|
||||
// call this once a frame to periodically log timers
|
||||
static void logStats();
|
||||
|
||||
bool mCollapsed; // don't show children
|
||||
|
||||
// statics
|
||||
static std::string sLogName;
|
||||
static bool sMetricLog,
|
||||
sLog;
|
||||
static U64 sClockResolution;
|
||||
};
|
||||
|
||||
typedef class LLFastTimer LLFastTimer;
|
||||
LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)
|
||||
{
|
||||
#if FAST_TIMER_ON
|
||||
mStartTime = TimeBlock::getCPUClockCount64();
|
||||
|
||||
BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
|
||||
TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
|
||||
accumulator->mActiveCount++;
|
||||
mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;
|
||||
// keep current parent as long as it is active when we are
|
||||
accumulator->mMoveUpTree |= (accumulator->mParent->getPrimaryAccumulator()->mActiveCount == 0);
|
||||
|
||||
// store top of stack
|
||||
mParentTimerData = *cur_timer_data;
|
||||
// push new information
|
||||
cur_timer_data->mActiveTimer = this;
|
||||
cur_timer_data->mTimeBlock = &timer;
|
||||
cur_timer_data->mChildTime = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE BlockTimer::~BlockTimer()
|
||||
{
|
||||
#if FAST_TIMER_ON
|
||||
U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
|
||||
BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
|
||||
TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();
|
||||
|
||||
accumulator->mCalls++;
|
||||
accumulator->mTotalTimeCounter += total_time - (accumulator->mTotalTimeCounter - mBlockStartTotalTimeCounter);
|
||||
accumulator->mSelfTimeCounter += total_time - cur_timer_data->mChildTime;
|
||||
accumulator->mActiveCount--;
|
||||
|
||||
// store last caller to bootstrap tree creation
|
||||
// do this in the destructor in case of recursion to get topmost caller
|
||||
accumulator->mLastCaller = mParentTimerData.mTimeBlock;
|
||||
|
||||
// we are only tracking self time, so subtract our total time delta from parents
|
||||
mParentTimerData.mChildTime += total_time;
|
||||
|
||||
//pop stack
|
||||
*cur_timer_data = mParentTimerData;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef LLTrace::BlockTimer LLFastTimer;
|
||||
|
||||
#endif // LL_LLFASTTIMER_H
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
*/
|
||||
|
||||
#if LL_WINDOWS
|
||||
#include <windows.h>
|
||||
#include "llwin32headerslean.h"
|
||||
#include <stdlib.h> // Windows errno
|
||||
#else
|
||||
#include <errno.h>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include "llwin32headers.h"
|
||||
#include <winnt.h>
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -28,10 +28,17 @@
|
|||
#include "linden_common.h"
|
||||
|
||||
#include "llinitparam.h"
|
||||
#include "llformat.h"
|
||||
|
||||
|
||||
namespace LLInitParam
|
||||
{
|
||||
|
||||
predicate_rule_t default_parse_rules()
|
||||
{
|
||||
return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY);
|
||||
}
|
||||
|
||||
//
|
||||
// Param
|
||||
//
|
||||
|
|
@ -164,6 +171,9 @@ namespace LLInitParam
|
|||
|
||||
bool BaseBlock::validateBlock(bool emit_errors) const
|
||||
{
|
||||
// only validate block when it hasn't already passed validation with current data
|
||||
if (!mValidated)
|
||||
{
|
||||
const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
|
||||
for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it)
|
||||
{
|
||||
|
|
@ -177,11 +187,18 @@ namespace LLInitParam
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
mValidated = true;
|
||||
}
|
||||
return mValidated;
|
||||
}
|
||||
|
||||
void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const
|
||||
bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const
|
||||
{
|
||||
bool serialized = false;
|
||||
if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// named param is one like LLView::Params::follows
|
||||
// unnamed param is like LLView::Params::rect - implicit
|
||||
const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
|
||||
|
|
@ -193,15 +210,10 @@ namespace LLInitParam
|
|||
param_handle_t param_handle = (*it)->mParamHandle;
|
||||
const Param* param = getParamFromHandle(param_handle);
|
||||
ParamDescriptor::serialize_func_t serialize_func = (*it)->mSerializeFunc;
|
||||
if (serialize_func)
|
||||
if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided())))
|
||||
{
|
||||
const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
|
||||
// each param descriptor remembers its serial number
|
||||
// so we can inspect the same param under different names
|
||||
// and see that it has the same number
|
||||
name_stack.push_back(std::make_pair("", true));
|
||||
serialize_func(*param, parser, name_stack, diff_param);
|
||||
name_stack.pop_back();
|
||||
serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +224,7 @@ namespace LLInitParam
|
|||
param_handle_t param_handle = it->second->mParamHandle;
|
||||
const Param* param = getParamFromHandle(param_handle);
|
||||
ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc;
|
||||
if (serialize_func && param->anyProvided())
|
||||
if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided())))
|
||||
{
|
||||
// Ensure this param has not already been serialized
|
||||
// Prevents <rect> from being serialized as its own tag.
|
||||
|
|
@ -237,10 +249,17 @@ namespace LLInitParam
|
|||
|
||||
name_stack.push_back(std::make_pair(it->first, !duplicate));
|
||||
const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
|
||||
serialize_func(*param, parser, name_stack, diff_param);
|
||||
serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param);
|
||||
name_stack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
|
||||
{
|
||||
serialized |= parser.writeValue(Flag(), name_stack);
|
||||
}
|
||||
// was anything serialized in this block?
|
||||
return serialized;
|
||||
}
|
||||
|
||||
bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const
|
||||
|
|
@ -359,7 +378,7 @@ namespace LLInitParam
|
|||
}
|
||||
|
||||
//static
|
||||
void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name)
|
||||
void BaseBlock::addParam(BlockDescriptor& block_data, ParamDescriptorPtr in_param, const char* char_name)
|
||||
{
|
||||
// create a copy of the param descriptor in mAllParams
|
||||
// so other data structures can store a pointer to it
|
||||
|
|
|
|||
|
|
@ -29,14 +29,15 @@
|
|||
#define LL_LLPARAM_H
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_enum.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "llerror.h"
|
||||
#include "llstl.h"
|
||||
#include "llpredicate.h"
|
||||
|
||||
namespace LLInitParam
|
||||
{
|
||||
|
|
@ -341,6 +342,19 @@ namespace LLInitParam
|
|||
|
||||
class Param;
|
||||
|
||||
enum ESerializePredicates
|
||||
{
|
||||
PROVIDED,
|
||||
REQUIRED,
|
||||
VALID,
|
||||
HAS_DEFAULT_VALUE,
|
||||
EMPTY
|
||||
};
|
||||
|
||||
typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t;
|
||||
|
||||
predicate_rule_t default_parse_rules();
|
||||
|
||||
// various callbacks and constraints associated with an individual param
|
||||
struct LL_COMMON_API ParamDescriptor
|
||||
{
|
||||
|
|
@ -351,8 +365,8 @@ namespace LLInitParam
|
|||
|
||||
typedef bool(*merge_func_t)(Param&, const Param&, bool);
|
||||
typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool);
|
||||
typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);
|
||||
typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count);
|
||||
typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t, const Param*);
|
||||
typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32, S32);
|
||||
typedef bool(*validation_func_t)(const Param*);
|
||||
|
||||
ParamDescriptor(param_handle_t p,
|
||||
|
|
@ -379,7 +393,7 @@ namespace LLInitParam
|
|||
UserData* mUserData;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
|
||||
typedef ParamDescriptor* ParamDescriptorPtr;
|
||||
|
||||
// each derived Block class keeps a static data structure maintaining offsets to various params
|
||||
class LL_COMMON_API BlockDescriptor
|
||||
|
|
@ -532,12 +546,28 @@ namespace LLInitParam
|
|||
LOG_CLASS(BaseBlock);
|
||||
friend class Param;
|
||||
|
||||
BaseBlock()
|
||||
: mValidated(false),
|
||||
mParamProvided(false)
|
||||
{}
|
||||
|
||||
virtual ~BaseBlock() {}
|
||||
bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false);
|
||||
|
||||
param_handle_t getHandleFromParam(const Param* param) const;
|
||||
bool validateBlock(bool emit_errors = true) const;
|
||||
|
||||
bool isProvided() const
|
||||
{
|
||||
return mParamProvided;
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return validateBlock(false);
|
||||
}
|
||||
|
||||
|
||||
Param* getParamFromHandle(const param_handle_t param_handle)
|
||||
{
|
||||
if (param_handle == 0) return NULL;
|
||||
|
|
@ -555,10 +585,19 @@ namespace LLInitParam
|
|||
void addSynonym(Param& param, const std::string& synonym);
|
||||
|
||||
// Blocks can override this to do custom tracking of changes
|
||||
virtual void paramChanged(const Param& changed_param, bool user_provided) {}
|
||||
virtual void paramChanged(const Param& changed_param, bool user_provided)
|
||||
{
|
||||
if (user_provided)
|
||||
{
|
||||
// a child param has been explicitly changed
|
||||
// so *some* aspect of this block is now provided
|
||||
mValidated = false;
|
||||
mParamProvided = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
|
||||
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
|
||||
bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const;
|
||||
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const;
|
||||
|
||||
virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); }
|
||||
|
|
@ -597,6 +636,9 @@ namespace LLInitParam
|
|||
return sBlockDescriptor;
|
||||
}
|
||||
|
||||
mutable bool mValidated; // lazy validation flag
|
||||
bool mParamProvided;
|
||||
|
||||
private:
|
||||
const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
|
||||
};
|
||||
|
|
@ -736,13 +778,11 @@ namespace LLInitParam
|
|||
typedef ParamValue<T, NAME_VALUE_LOOKUP, true> self_t;
|
||||
|
||||
ParamValue()
|
||||
: T(),
|
||||
mValidated(false)
|
||||
: T()
|
||||
{}
|
||||
|
||||
ParamValue(value_assignment_t other)
|
||||
: T(other),
|
||||
mValidated(false)
|
||||
: T(other)
|
||||
{}
|
||||
|
||||
void setValue(value_assignment_t val)
|
||||
|
|
@ -784,9 +824,6 @@ namespace LLInitParam
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable bool mValidated; // lazy validation flag
|
||||
};
|
||||
|
||||
template<typename NAME_VALUE_LOOKUP>
|
||||
|
|
@ -884,12 +921,14 @@ namespace LLInitParam
|
|||
|
||||
bool isProvided() const { return Param::anyProvided(); }
|
||||
|
||||
bool isValid() const { return true; }
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
self_t& typed_param = static_cast<self_t&>(param);
|
||||
// no further names in stack, attempt to parse value now
|
||||
if (name_stack_range.first == name_stack_range.second)
|
||||
{
|
||||
{
|
||||
std::string name;
|
||||
|
||||
// try to parse a known named value
|
||||
|
|
@ -905,17 +944,30 @@ namespace LLInitParam
|
|||
else if (parser.readValue(typed_param.getValue()))
|
||||
{
|
||||
typed_param.clearValueName();
|
||||
typed_param.setProvided();
|
||||
return true;
|
||||
}
|
||||
typed_param.setProvided();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
|
||||
static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
|
||||
{
|
||||
bool serialized = false;
|
||||
const self_t& typed_param = static_cast<const self_t&>(param);
|
||||
if (!typed_param.isProvided()) return;
|
||||
const self_t* diff_typed_param = static_cast<const self_t*>(diff_param);
|
||||
|
||||
LLPredicate::Value<ESerializePredicates> predicate;
|
||||
if (diff_typed_param && ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue()))
|
||||
{
|
||||
predicate.set(HAS_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
predicate.set(VALID, typed_param.isValid());
|
||||
predicate.set(PROVIDED, typed_param.anyProvided());
|
||||
predicate.set(EMPTY, false);
|
||||
|
||||
if (!predicate_rule.check(predicate)) return false;
|
||||
|
||||
if (!name_stack.empty())
|
||||
{
|
||||
|
|
@ -928,23 +980,25 @@ namespace LLInitParam
|
|||
|
||||
if (!key.empty())
|
||||
{
|
||||
if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
|
||||
if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key))
|
||||
{
|
||||
parser.writeValue(key, name_stack);
|
||||
serialized = parser.writeValue(key, name_stack);
|
||||
}
|
||||
}
|
||||
// then try to serialize value directly
|
||||
else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), static_cast<const self_t*>(diff_param)->getValue()))
|
||||
else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue()))
|
||||
{
|
||||
if (!parser.writeValue(typed_param.getValue(), name_stack))
|
||||
serialized = parser.writeValue(typed_param.getValue(), name_stack);
|
||||
if (!serialized)
|
||||
{
|
||||
std::string calculated_key = typed_param.calcValueName(typed_param.getValue());
|
||||
if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))
|
||||
if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), calculated_key))
|
||||
{
|
||||
parser.writeValue(calculated_key, name_stack);
|
||||
serialized = parser.writeValue(calculated_key, name_stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
|
||||
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
|
||||
|
|
@ -995,15 +1049,15 @@ namespace LLInitParam
|
|||
};
|
||||
|
||||
// parameter that is a block
|
||||
template <typename T, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<T, NAME_VALUE_LOOKUP, false, true>
|
||||
template <typename BLOCK_T, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, true>
|
||||
: public Param,
|
||||
public ParamValue<T, NAME_VALUE_LOOKUP>
|
||||
public ParamValue<BLOCK_T, NAME_VALUE_LOOKUP>
|
||||
{
|
||||
public:
|
||||
typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
|
||||
typedef ParamValue<BLOCK_T, NAME_VALUE_LOOKUP> param_value_t;
|
||||
typedef typename param_value_t::value_assignment_t value_assignment_t;
|
||||
typedef TypedParam<T, NAME_VALUE_LOOKUP, false, true> self_t;
|
||||
typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, true> self_t;
|
||||
typedef NAME_VALUE_LOOKUP name_value_lookup_t;
|
||||
|
||||
using param_value_t::operator();
|
||||
|
|
@ -1037,28 +1091,34 @@ namespace LLInitParam
|
|||
if(name_value_lookup_t::valueNamesExist()
|
||||
&& parser.readValue(name)
|
||||
&& name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
|
||||
{
|
||||
{
|
||||
typed_param.setValueName(name);
|
||||
typed_param.setProvided();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(typed_param.deserializeBlock(parser, name_stack_range, new_name))
|
||||
{ // attempt to parse block...
|
||||
typed_param.clearValueName();
|
||||
typed_param.setProvided();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(typed_param.deserializeBlock(parser, name_stack_range, new_name))
|
||||
{ // attempt to parse block...
|
||||
typed_param.clearValueName();
|
||||
typed_param.setProvided();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
|
||||
static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
|
||||
{
|
||||
const self_t& typed_param = static_cast<const self_t&>(param);
|
||||
if (!typed_param.isProvided()) return;
|
||||
|
||||
LLPredicate::Value<ESerializePredicates> predicate;
|
||||
|
||||
predicate.set(VALID, typed_param.isValid());
|
||||
predicate.set(PROVIDED, typed_param.anyProvided());
|
||||
|
||||
if (!predicate_rule.check(predicate)) return false;
|
||||
|
||||
if (!name_stack.empty())
|
||||
{
|
||||
|
|
@ -1068,15 +1128,17 @@ namespace LLInitParam
|
|||
std::string key = typed_param.getValueName();
|
||||
if (!key.empty())
|
||||
{
|
||||
if (!parser.writeValue(key, name_stack))
|
||||
if (parser.writeValue(key, name_stack))
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
typed_param.serializeBlock(parser, name_stack, static_cast<const self_t*>(diff_param));
|
||||
return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
|
||||
|
|
@ -1090,23 +1152,16 @@ namespace LLInitParam
|
|||
// *and* the block as a whole validates
|
||||
bool isProvided() const
|
||||
{
|
||||
// only validate block when it hasn't already passed validation with current data
|
||||
if (Param::anyProvided() && !param_value_t::mValidated)
|
||||
{
|
||||
// a sub-block is "provided" when it has been filled in enough to be valid
|
||||
param_value_t::mValidated = param_value_t::validateBlock(false);
|
||||
}
|
||||
return Param::anyProvided() && param_value_t::mValidated;
|
||||
return Param::anyProvided() && isValid();
|
||||
}
|
||||
|
||||
using param_value_t::isValid;
|
||||
|
||||
// assign block contents to this param-that-is-a-block
|
||||
void set(value_assignment_t val, bool flag_as_provided = true)
|
||||
{
|
||||
setValue(val);
|
||||
param_value_t::clearValueName();
|
||||
// force revalidation of block
|
||||
// next call to isProvided() will update provision status based on validity
|
||||
param_value_t::mValidated = false;
|
||||
setProvided(flag_as_provided);
|
||||
}
|
||||
|
||||
|
|
@ -1121,9 +1176,6 @@ namespace LLInitParam
|
|||
param_value_t::paramChanged(changed_param, user_provided);
|
||||
if (user_provided)
|
||||
{
|
||||
// a child param has been explicitly changed
|
||||
// so *some* aspect of this block is now provided
|
||||
param_value_t::mValidated = false;
|
||||
setProvided();
|
||||
param_value_t::clearValueName();
|
||||
}
|
||||
|
|
@ -1161,13 +1213,13 @@ namespace LLInitParam
|
|||
};
|
||||
|
||||
// container of non-block parameters
|
||||
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false>
|
||||
template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, false>
|
||||
: public Param
|
||||
{
|
||||
public:
|
||||
typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false> self_t;
|
||||
typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
|
||||
typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, false> self_t;
|
||||
typedef ParamValue<MULTI_VALUE_T, NAME_VALUE_LOOKUP> param_value_t;
|
||||
typedef typename std::vector<param_value_t> container_t;
|
||||
typedef const container_t& value_assignment_t;
|
||||
|
||||
|
|
@ -1175,7 +1227,9 @@ namespace LLInitParam
|
|||
typedef NAME_VALUE_LOOKUP name_value_lookup_t;
|
||||
|
||||
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
|
||||
: Param(block_descriptor.mCurrentBlockPtr)
|
||||
: Param(block_descriptor.mCurrentBlockPtr),
|
||||
mMinCount(min_count),
|
||||
mMaxCount(max_count)
|
||||
{
|
||||
std::copy(value.begin(), value.end(), std::back_inserter(mValues));
|
||||
|
||||
|
|
@ -1193,15 +1247,29 @@ namespace LLInitParam
|
|||
}
|
||||
}
|
||||
|
||||
bool isProvided() const { return Param::anyProvided(); }
|
||||
bool isProvided() const { return Param::anyProvided() && isValid(); }
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
size_t num_elements = numValidElements();
|
||||
return mMinCount < num_elements && num_elements < mMaxCount;
|
||||
}
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
Parser::name_stack_range_t new_name_stack_range(name_stack_range);
|
||||
self_t& typed_param = static_cast<self_t&>(param);
|
||||
value_t value;
|
||||
|
||||
// pop first element if empty string
|
||||
if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
|
||||
{
|
||||
++new_name_stack_range.first;
|
||||
}
|
||||
|
||||
// no further names in stack, attempt to parse value now
|
||||
if (name_stack_range.first == name_stack_range.second)
|
||||
{
|
||||
if (new_name_stack_range.first == new_name_stack_range.second)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
// try to parse a known named value
|
||||
|
|
@ -1214,25 +1282,34 @@ namespace LLInitParam
|
|||
return true;
|
||||
}
|
||||
else if (parser.readValue(value)) // attempt to read value directly
|
||||
{
|
||||
typed_param.add(value);
|
||||
return true;
|
||||
}
|
||||
{
|
||||
typed_param.add(value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
|
||||
static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
|
||||
{
|
||||
bool serialized = false;
|
||||
const self_t& typed_param = static_cast<const self_t&>(param);
|
||||
if (!typed_param.isProvided() || name_stack.empty()) return;
|
||||
|
||||
LLPredicate::Value<ESerializePredicates> predicate;
|
||||
|
||||
predicate.set(REQUIRED, typed_param.mMinCount > 0);
|
||||
predicate.set(VALID, typed_param.isValid());
|
||||
predicate.set(PROVIDED, typed_param.anyProvided());
|
||||
predicate.set(EMPTY, typed_param.mValues.empty());
|
||||
|
||||
if (!predicate_rule.check(predicate)) return false;
|
||||
|
||||
for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
std::string key = it->getValueName();
|
||||
name_stack.back().second = true;
|
||||
name_stack.push_back(std::make_pair(std::string(), true));
|
||||
|
||||
if(key.empty())
|
||||
// not parsed via name values, write out value directly
|
||||
|
|
@ -1241,7 +1318,11 @@ namespace LLInitParam
|
|||
if (!value_written)
|
||||
{
|
||||
std::string calculated_key = it->calcValueName(it->getValue());
|
||||
if (!parser.writeValue(calculated_key, name_stack))
|
||||
if (parser.writeValue(calculated_key, name_stack))
|
||||
{
|
||||
serialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -1249,17 +1330,30 @@ namespace LLInitParam
|
|||
}
|
||||
else
|
||||
{
|
||||
if(!parser.writeValue(key, name_stack))
|
||||
if(parser.writeValue(key, name_stack))
|
||||
{
|
||||
serialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
name_stack.pop_back();
|
||||
}
|
||||
|
||||
if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
|
||||
{
|
||||
serialized |= parser.writeValue(Flag(), name_stack);
|
||||
}
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
|
||||
{
|
||||
parser.inspectValue<VALUE_TYPE>(name_stack, min_count, max_count, NULL);
|
||||
parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL);
|
||||
if (name_value_lookup_t::getPossibleValues())
|
||||
{
|
||||
parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues());
|
||||
|
|
@ -1316,7 +1410,7 @@ namespace LLInitParam
|
|||
bool empty() const { return mValues.empty(); }
|
||||
size_t size() const { return mValues.size(); }
|
||||
|
||||
U32 numValidElements() const
|
||||
size_t numValidElements() const
|
||||
{
|
||||
return mValues.size();
|
||||
}
|
||||
|
|
@ -1346,23 +1440,27 @@ namespace LLInitParam
|
|||
}
|
||||
|
||||
container_t mValues;
|
||||
size_t mMinCount,
|
||||
mMaxCount;
|
||||
};
|
||||
|
||||
// container of block parameters
|
||||
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true>
|
||||
template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP>
|
||||
class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, true>
|
||||
: public Param
|
||||
{
|
||||
public:
|
||||
typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true> self_t;
|
||||
typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP> param_value_t;
|
||||
typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, true> self_t;
|
||||
typedef ParamValue<MULTI_BLOCK_T, NAME_VALUE_LOOKUP> param_value_t;
|
||||
typedef typename std::vector<param_value_t> container_t;
|
||||
typedef const container_t& value_assignment_t;
|
||||
typedef typename param_value_t::value_t value_t;
|
||||
typedef NAME_VALUE_LOOKUP name_value_lookup_t;
|
||||
|
||||
TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
|
||||
: Param(block_descriptor.mCurrentBlockPtr)
|
||||
: Param(block_descriptor.mCurrentBlockPtr),
|
||||
mMinCount(min_count),
|
||||
mMaxCount(max_count)
|
||||
{
|
||||
std::copy(value.begin(), value.end(), back_inserter(mValues));
|
||||
|
||||
|
|
@ -1380,14 +1478,30 @@ namespace LLInitParam
|
|||
}
|
||||
}
|
||||
|
||||
bool isProvided() const { return Param::anyProvided(); }
|
||||
bool isProvided() const { return Param::anyProvided() && isValid(); }
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
size_t num_elements = numValidElements();
|
||||
return mMinCount < num_elements && num_elements < mMaxCount;
|
||||
}
|
||||
|
||||
|
||||
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
|
||||
{
|
||||
Parser::name_stack_range_t new_name_stack_range(name_stack_range);
|
||||
self_t& typed_param = static_cast<self_t&>(param);
|
||||
bool new_value = false;
|
||||
bool new_array_value = false;
|
||||
|
||||
if (new_name || typed_param.mValues.empty())
|
||||
// pop first element if empty string
|
||||
if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
|
||||
{
|
||||
new_array_value = new_name_stack_range.first->second;
|
||||
++new_name_stack_range.first;
|
||||
}
|
||||
|
||||
if (new_name || new_array_value || typed_param.mValues.empty())
|
||||
{
|
||||
new_value = true;
|
||||
typed_param.mValues.push_back(value_t());
|
||||
|
|
@ -1395,26 +1509,34 @@ namespace LLInitParam
|
|||
|
||||
param_value_t& value = typed_param.mValues.back();
|
||||
|
||||
if (name_stack_range.first == name_stack_range.second)
|
||||
if (new_name_stack_range.first == new_name_stack_range.second)
|
||||
{ // try to parse a known named value
|
||||
std::string name;
|
||||
|
||||
if(name_value_lookup_t::valueNamesExist()
|
||||
&& parser.readValue(name)
|
||||
&& name_value_lookup_t::getValueFromName(name, value.getValue()))
|
||||
{
|
||||
{
|
||||
typed_param.mValues.back().setValueName(name);
|
||||
typed_param.setProvided();
|
||||
return true;
|
||||
typed_param.setProvided();
|
||||
if (new_array_value)
|
||||
{
|
||||
name_stack_range.first->second = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// attempt to parse block...
|
||||
if(value.deserializeBlock(parser, name_stack_range, new_name))
|
||||
{
|
||||
typed_param.setProvided();
|
||||
return true;
|
||||
}
|
||||
{
|
||||
typed_param.setProvided();
|
||||
if (new_array_value)
|
||||
{
|
||||
name_stack_range.first->second = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (new_value)
|
||||
|
|
@ -1425,29 +1547,47 @@ namespace LLInitParam
|
|||
return false;
|
||||
}
|
||||
|
||||
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
|
||||
static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
|
||||
{
|
||||
bool serialized = false;
|
||||
const self_t& typed_param = static_cast<const self_t&>(param);
|
||||
if (!typed_param.isProvided() || name_stack.empty()) return;
|
||||
|
||||
LLPredicate::Value<ESerializePredicates> predicate;
|
||||
|
||||
predicate.set(REQUIRED, typed_param.mMinCount > 0);
|
||||
predicate.set(VALID, typed_param.isValid());
|
||||
predicate.set(PROVIDED, typed_param.anyProvided());
|
||||
predicate.set(EMPTY, typed_param.mValues.empty());
|
||||
|
||||
if (!predicate_rule.check(predicate)) return false;
|
||||
|
||||
for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
name_stack.back().second = true;
|
||||
name_stack.push_back(std::make_pair(std::string(), true));
|
||||
|
||||
std::string key = it->getValueName();
|
||||
if (!key.empty())
|
||||
{
|
||||
parser.writeValue(key, name_stack);
|
||||
serialized |= parser.writeValue(key, name_stack);
|
||||
}
|
||||
// Not parsed via named values, write out value directly
|
||||
// NOTE: currently we don't worry about removing default values in Multiple
|
||||
// NOTE: currently we don't do diffing of Multiples
|
||||
else
|
||||
{
|
||||
it->serializeBlock(parser, name_stack, NULL);
|
||||
serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL);
|
||||
}
|
||||
|
||||
name_stack.pop_back();
|
||||
}
|
||||
|
||||
if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
|
||||
{
|
||||
serialized |= parser.writeValue(Flag(), name_stack);
|
||||
}
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
|
||||
|
|
@ -1503,14 +1643,14 @@ namespace LLInitParam
|
|||
bool empty() const { return mValues.empty(); }
|
||||
size_t size() const { return mValues.size(); }
|
||||
|
||||
U32 numValidElements() const
|
||||
size_t numValidElements() const
|
||||
{
|
||||
U32 count = 0;
|
||||
size_t count = 0;
|
||||
for (const_iterator it = mValues.begin(), end_it = mValues.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
if(it->validateBlock(false)) count++;
|
||||
if(it->isValid()) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
|
@ -1542,6 +1682,8 @@ namespace LLInitParam
|
|||
}
|
||||
|
||||
container_t mValues;
|
||||
size_t mMinCount,
|
||||
mMaxCount;
|
||||
};
|
||||
|
||||
template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
|
||||
|
|
@ -1829,7 +1971,7 @@ namespace LLInitParam
|
|||
|
||||
static bool validate(const Param* paramp)
|
||||
{
|
||||
U32 num_valid = ((super_t*)paramp)->numValidElements();
|
||||
size_t num_valid = ((super_t*)paramp)->numValidElements();
|
||||
return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount;
|
||||
}
|
||||
};
|
||||
|
|
@ -1946,13 +2088,11 @@ namespace LLInitParam
|
|||
typedef block_t value_t;
|
||||
|
||||
ParamValue()
|
||||
: block_t(),
|
||||
mValidated(false)
|
||||
: block_t()
|
||||
{}
|
||||
|
||||
ParamValue(value_assignment_t other)
|
||||
: block_t(other),
|
||||
mValidated(false)
|
||||
: block_t(other)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1980,9 +2120,6 @@ namespace LLInitParam
|
|||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable bool mValidated; // lazy validation flag
|
||||
};
|
||||
|
||||
template<typename T, bool IS_BLOCK>
|
||||
|
|
@ -1997,13 +2134,11 @@ namespace LLInitParam
|
|||
typedef T value_t;
|
||||
|
||||
ParamValue()
|
||||
: mValue(),
|
||||
mValidated(false)
|
||||
: mValue()
|
||||
{}
|
||||
|
||||
ParamValue(value_assignment_t other)
|
||||
: mValue(other),
|
||||
mValidated(false)
|
||||
: mValue(other)
|
||||
{}
|
||||
|
||||
void setValue(value_assignment_t val)
|
||||
|
|
@ -2036,11 +2171,11 @@ namespace LLInitParam
|
|||
return mValue.get().deserializeBlock(p, name_stack_range, new_name);
|
||||
}
|
||||
|
||||
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
|
||||
bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const
|
||||
{
|
||||
if (mValue.empty()) return;
|
||||
if (mValue.empty()) return false;
|
||||
|
||||
mValue.get().serializeBlock(p, name_stack, diff_block);
|
||||
return mValue.get().serializeBlock(p, name_stack, predicate_rule, diff_block);
|
||||
}
|
||||
|
||||
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
|
||||
|
|
@ -2050,9 +2185,6 @@ namespace LLInitParam
|
|||
return mValue.get().inspectBlock(p, name_stack, min_count, max_count);
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable bool mValidated; // lazy validation flag
|
||||
|
||||
private:
|
||||
BaseBlock::Lazy<T> mValue;
|
||||
};
|
||||
|
|
@ -2069,12 +2201,10 @@ namespace LLInitParam
|
|||
typedef const LLSD& value_assignment_t;
|
||||
|
||||
ParamValue()
|
||||
: mValidated(false)
|
||||
{}
|
||||
|
||||
ParamValue(value_assignment_t other)
|
||||
: mValue(other),
|
||||
mValidated(false)
|
||||
: mValue(other)
|
||||
{}
|
||||
|
||||
void setValue(value_assignment_t val) { mValue = val; }
|
||||
|
|
@ -2088,16 +2218,13 @@ namespace LLInitParam
|
|||
|
||||
// block param interface
|
||||
LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
|
||||
LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
|
||||
LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const;
|
||||
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
|
||||
{
|
||||
//TODO: implement LLSD params as schema type Any
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable bool mValidated; // lazy validation flag
|
||||
|
||||
private:
|
||||
static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack);
|
||||
|
||||
|
|
@ -2126,8 +2253,7 @@ namespace LLInitParam
|
|||
|
||||
CustomParamValue(const T& value = T())
|
||||
: mValue(value),
|
||||
mValueAge(VALUE_AUTHORITATIVE),
|
||||
mValidated(false)
|
||||
mValueAge(VALUE_AUTHORITATIVE)
|
||||
{}
|
||||
|
||||
bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name)
|
||||
|
|
@ -2151,7 +2277,7 @@ namespace LLInitParam
|
|||
return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name);
|
||||
}
|
||||
|
||||
void serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
|
||||
bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const
|
||||
{
|
||||
const derived_t& typed_param = static_cast<const derived_t&>(*this);
|
||||
const derived_t* diff_param = static_cast<const derived_t*>(diff_block);
|
||||
|
|
@ -2163,14 +2289,18 @@ namespace LLInitParam
|
|||
{
|
||||
if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key))
|
||||
{
|
||||
parser.writeValue(key, name_stack);
|
||||
return parser.writeValue(key, name_stack);
|
||||
}
|
||||
}
|
||||
// then try to serialize value directly
|
||||
else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))
|
||||
{
|
||||
|
||||
if (!parser.writeValue(typed_param.getValue(), name_stack))
|
||||
if (parser.writeValue(typed_param.getValue(), name_stack))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//RN: *always* serialize provided components of BlockValue (don't pass diff_param on),
|
||||
// since these tend to be viewed as the constructor arguments for the value T. It seems
|
||||
|
|
@ -2187,14 +2317,15 @@ namespace LLInitParam
|
|||
// and serialize those params
|
||||
derived_t copy(typed_param);
|
||||
copy.updateBlockFromValue(true);
|
||||
copy.block_t::serializeBlock(parser, name_stack, NULL);
|
||||
return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
block_t::serializeBlock(parser, name_stack, NULL);
|
||||
return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const
|
||||
|
|
@ -2312,8 +2443,6 @@ namespace LLInitParam
|
|||
return block_t::mergeBlock(block_data, source, overwrite);
|
||||
}
|
||||
|
||||
mutable bool mValidated; // lazy validation flag
|
||||
|
||||
private:
|
||||
mutable T mValue;
|
||||
mutable EValueAge mValueAge;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llinstancetracker.h"
|
||||
#include "llapr.h"
|
||||
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
|
|
@ -47,3 +49,19 @@ void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
|
|||
InstancesMap::mapped_type()))
|
||||
.first->second;
|
||||
}
|
||||
|
||||
void LLInstanceTrackerBase::StaticBase::incrementDepth()
|
||||
{
|
||||
apr_atomic_inc32(&sIterationNestDepth);
|
||||
}
|
||||
|
||||
void LLInstanceTrackerBase::StaticBase::decrementDepth()
|
||||
{
|
||||
apr_atomic_dec32(&sIterationNestDepth);
|
||||
}
|
||||
|
||||
U32 LLInstanceTrackerBase::StaticBase::getDepth()
|
||||
{
|
||||
apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth);
|
||||
return data;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,15 +70,20 @@ protected:
|
|||
StaticBase():
|
||||
sIterationNestDepth(0)
|
||||
{}
|
||||
S32 sIterationNestDepth;
|
||||
|
||||
void incrementDepth();
|
||||
void decrementDepth();
|
||||
U32 getDepth();
|
||||
private:
|
||||
U32 sIterationNestDepth;
|
||||
};
|
||||
};
|
||||
|
||||
/// This mix-in class adds support for tracking all instances of the specified class parameter T
|
||||
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
|
||||
/// If KEY is not provided, then instances are stored in a simple set
|
||||
/// @NOTE: see explicit specialization below for default KEY==T* case
|
||||
template<typename T, typename KEY = T*>
|
||||
/// @NOTE: see explicit specialization below for default KEY==void case
|
||||
template<typename T, typename KEY = void>
|
||||
class LLInstanceTracker : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef LLInstanceTracker<T, KEY> MyT;
|
||||
|
|
@ -99,12 +104,12 @@ public:
|
|||
instance_iter(const typename InstanceMap::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
getStatic().decrementDepth();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -133,18 +138,18 @@ public:
|
|||
key_iter(typename InstanceMap::iterator it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
key_iter(const key_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
~key_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
getStatic().decrementDepth();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -203,7 +208,7 @@ protected:
|
|||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
llassert_always(getStatic().getDepth() == 0);
|
||||
remove_();
|
||||
}
|
||||
virtual void setKey(KEY key) { remove_(); add_(key); }
|
||||
|
|
@ -224,12 +229,12 @@ private:
|
|||
KEY mInstanceKey;
|
||||
};
|
||||
|
||||
/// explicit specialization for default case where KEY is T*
|
||||
/// explicit specialization for default case where KEY is void
|
||||
/// use a simple std::set<T*>
|
||||
template<typename T>
|
||||
class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
|
||||
class LLInstanceTracker<T, void> : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef LLInstanceTracker<T, T*> MyT;
|
||||
typedef LLInstanceTracker<T, void> MyT;
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
struct StaticData: public StaticBase
|
||||
{
|
||||
|
|
@ -262,18 +267,18 @@ public:
|
|||
instance_iter(const typename InstanceSet::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
instance_iter(const instance_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
getStatic().incrementDepth();
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
getStatic().decrementDepth();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -306,7 +311,7 @@ protected:
|
|||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
llassert_always(getStatic().getDepth() == 0);
|
||||
getSet_().erase(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ public:
|
|||
LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN));
|
||||
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
|
||||
LLSD nop;
|
||||
F64 until(LLTimer::getElapsedSeconds() + 2);
|
||||
F64 until = (LLTimer::getElapsedSeconds() + 2).value();
|
||||
while (childin.size() && LLTimer::getElapsedSeconds() < until)
|
||||
{
|
||||
mainloop.post(nop);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ documentation and/or software.
|
|||
|
||||
#include "llmd5.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream> // cerr
|
||||
|
||||
// how many bytes to grab at a time when checking files
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
//#endif
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
//# include <windows.h>
|
||||
# include <psapi.h>
|
||||
#elif defined(LL_DARWIN)
|
||||
# include <sys/types.h>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
#define LLMEMORY_H
|
||||
|
||||
#include "linden_common.h"
|
||||
#if !LL_WINDOWS
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
class LLMutex ;
|
||||
|
||||
|
|
@ -36,6 +39,20 @@ class LLMutex ;
|
|||
#define LL_CHECK_MEMORY
|
||||
#endif
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define LL_ALIGN_OF __alignof
|
||||
#else
|
||||
#define LL_ALIGN_OF __align_of__
|
||||
#endif
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define LL_DEFAULT_HEAP_ALIGN 8
|
||||
#elif LL_DARWIN
|
||||
#define LL_DEFAULT_HEAP_ALIGN 16
|
||||
#elif LL_LINUX
|
||||
#define LL_DEFAULT_HEAP_ALIGN 8
|
||||
#endif
|
||||
|
||||
inline void* ll_aligned_malloc( size_t size, int align )
|
||||
{
|
||||
void* mem = malloc( size + (align - 1) + sizeof(void*) );
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@
|
|||
#include "indra_constants.h"
|
||||
#include "llerror.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llstat.h"
|
||||
#include "lltreeiterators.h"
|
||||
#include "llmetricperformancetester.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------------
|
||||
// LLMetricPerformanceTesterBasic : static methods and testers management
|
||||
|
|
@ -91,7 +91,7 @@ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::s
|
|||
// Return TRUE if this metric is requested or if the general default "catch all" metric is requested
|
||||
BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name)
|
||||
{
|
||||
return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME)));
|
||||
return (LLTrace::TimeBlock::sMetricLog && ((LLTrace::TimeBlock::sLogName == name) || (LLTrace::TimeBlock::sLogName == DEFAULT_METRIC_NAME)));
|
||||
}
|
||||
|
||||
/*static*/
|
||||
|
|
@ -194,8 +194,7 @@ void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
|
|||
|
||||
void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
|
||||
{
|
||||
LLMutexLock lock(LLFastTimer::sLogLock);
|
||||
LLFastTimer::sLogQueue.push((*sd));
|
||||
LLTrace::TimeBlock::pushLog(*sd);
|
||||
}
|
||||
|
||||
void LLMetricPerformanceTesterBasic::outputTestResults()
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#define LLMORTICIAN_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include <list>
|
||||
|
||||
class LL_COMMON_API LLMortician
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,179 @@
|
|||
/**
|
||||
* @file llmutex.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llapr.h"
|
||||
|
||||
#include "apr_portable.h"
|
||||
|
||||
#include "llmutex.h"
|
||||
#include "llthread.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
LLMutex::LLMutex(apr_pool_t *poolp) :
|
||||
mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
|
||||
{
|
||||
//if (poolp)
|
||||
//{
|
||||
// mIsLocalPool = FALSE;
|
||||
// mAPRPoolp = poolp;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
mIsLocalPool = TRUE;
|
||||
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
|
||||
}
|
||||
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
|
||||
}
|
||||
|
||||
|
||||
LLMutex::~LLMutex()
|
||||
{
|
||||
#if MUTEX_DEBUG
|
||||
//bad assertion, the subclass LLSignal might be "locked", and that's OK
|
||||
//llassert_always(!isLocked()); // better not be locked!
|
||||
#endif
|
||||
if (ll_apr_is_initialized())
|
||||
{
|
||||
apr_thread_mutex_destroy(mAPRMutexp);
|
||||
if (mIsLocalPool)
|
||||
{
|
||||
apr_pool_destroy(mAPRPoolp);
|
||||
}
|
||||
}
|
||||
mAPRMutexp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLMutex::lock()
|
||||
{
|
||||
if(isSelfLocked())
|
||||
{ //redundant lock
|
||||
mCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
apr_thread_mutex_lock(mAPRMutexp);
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
// Have to have the lock before we can access the debug info
|
||||
U32 id = LLThread::currentID();
|
||||
if (mIsLocked[id] != FALSE)
|
||||
llerrs << "Already locked in Thread: " << id << llendl;
|
||||
mIsLocked[id] = TRUE;
|
||||
#endif
|
||||
|
||||
mLockingThread = LLThread::currentID();
|
||||
}
|
||||
|
||||
void LLMutex::unlock()
|
||||
{
|
||||
if (mCount > 0)
|
||||
{ //not the root unlock
|
||||
mCount--;
|
||||
return;
|
||||
}
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
// Access the debug info while we have the lock
|
||||
U32 id = LLThread::currentID();
|
||||
if (mIsLocked[id] != TRUE)
|
||||
llerrs << "Not locked in Thread: " << id << llendl;
|
||||
mIsLocked[id] = FALSE;
|
||||
#endif
|
||||
|
||||
mLockingThread = NO_THREAD;
|
||||
apr_thread_mutex_unlock(mAPRMutexp);
|
||||
}
|
||||
|
||||
bool LLMutex::isLocked()
|
||||
{
|
||||
apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
|
||||
if (APR_STATUS_IS_EBUSY(status))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
apr_thread_mutex_unlock(mAPRMutexp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLMutex::isSelfLocked()
|
||||
{
|
||||
return mLockingThread == LLThread::currentID();
|
||||
}
|
||||
|
||||
U32 LLMutex::lockingThread() const
|
||||
{
|
||||
return mLockingThread;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
LLCondition::LLCondition(apr_pool_t *poolp) :
|
||||
LLMutex(poolp)
|
||||
{
|
||||
// base class (LLMutex) has already ensured that mAPRPoolp is set up.
|
||||
|
||||
apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
|
||||
}
|
||||
|
||||
|
||||
LLCondition::~LLCondition()
|
||||
{
|
||||
apr_thread_cond_destroy(mAPRCondp);
|
||||
mAPRCondp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLCondition::wait()
|
||||
{
|
||||
if (!isLocked())
|
||||
{ //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
|
||||
apr_thread_mutex_lock(mAPRMutexp);
|
||||
#if MUTEX_DEBUG
|
||||
// avoid asserts on destruction in non-release builds
|
||||
U32 id = LLThread::currentID();
|
||||
mIsLocked[id] = TRUE;
|
||||
#endif
|
||||
}
|
||||
apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
|
||||
}
|
||||
|
||||
void LLCondition::signal()
|
||||
{
|
||||
apr_thread_cond_signal(mAPRCondp);
|
||||
}
|
||||
|
||||
void LLCondition::broadcast()
|
||||
{
|
||||
apr_thread_cond_broadcast(mAPRCondp);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* @file llmutex.h
|
||||
* @brief Base classes for mutex and condition handling.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLMUTEX_H
|
||||
#define LL_LLMUTEX_H
|
||||
|
||||
#include "llapr.h"
|
||||
#include "apr_thread_cond.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
|
||||
|
||||
class LL_COMMON_API LLMutex
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
NO_THREAD = 0xFFFFFFFF
|
||||
} e_locking_thread;
|
||||
|
||||
LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex
|
||||
virtual ~LLMutex();
|
||||
|
||||
void lock(); // blocks
|
||||
void unlock();
|
||||
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
|
||||
bool isSelfLocked(); //return true if locked in a same thread
|
||||
U32 lockingThread() const; //get ID of locking thread
|
||||
|
||||
protected:
|
||||
apr_thread_mutex_t *mAPRMutexp;
|
||||
mutable U32 mCount;
|
||||
mutable U32 mLockingThread;
|
||||
|
||||
apr_pool_t *mAPRPoolp;
|
||||
BOOL mIsLocalPool;
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
std::map<U32, BOOL> mIsLocked;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
|
||||
class LL_COMMON_API LLCondition : public LLMutex
|
||||
{
|
||||
public:
|
||||
LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
|
||||
~LLCondition();
|
||||
|
||||
void wait(); // blocks
|
||||
void signal();
|
||||
void broadcast();
|
||||
|
||||
protected:
|
||||
apr_thread_cond_t *mAPRCondp;
|
||||
};
|
||||
|
||||
class LLMutexLock
|
||||
{
|
||||
public:
|
||||
LLMutexLock(LLMutex* mutex)
|
||||
{
|
||||
mMutex = mutex;
|
||||
|
||||
if(mMutex)
|
||||
mMutex->lock();
|
||||
}
|
||||
~LLMutexLock()
|
||||
{
|
||||
if(mMutex)
|
||||
mMutex->unlock();
|
||||
}
|
||||
private:
|
||||
LLMutex* mMutex;
|
||||
};
|
||||
|
||||
#endif // LL_LLTHREAD_H
|
||||
|
|
@ -97,24 +97,13 @@ public:
|
|||
|
||||
LLPointer<Type>& operator =(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
|
||||
assign(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
assign(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -122,12 +111,7 @@ public:
|
|||
template<typename Subclass>
|
||||
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.get() )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.get();
|
||||
ref();
|
||||
}
|
||||
assign(ptr.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -144,6 +128,16 @@ protected:
|
|||
void ref();
|
||||
void unref();
|
||||
#else
|
||||
|
||||
void assign(const LLPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
}
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
|
|
@ -156,9 +150,9 @@ protected:
|
|||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
Type *temp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
temp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
|
|
@ -171,4 +165,53 @@ protected:
|
|||
Type* mPointer;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class LLCopyOnWritePointer
|
||||
{
|
||||
public:
|
||||
typedef LLCopyOnWritePointer<Type> self_t;
|
||||
|
||||
LLCopyOnWritePointer()
|
||||
{}
|
||||
|
||||
LLCopyOnWritePointer(Type* ptr)
|
||||
: mPointer(ptr)
|
||||
{}
|
||||
|
||||
LLCopyOnWritePointer(LLPointer<Type>& ptr)
|
||||
: mPointer(ptr)
|
||||
{}
|
||||
|
||||
Type* write()
|
||||
{
|
||||
makeUnique();
|
||||
return mPointer.get();
|
||||
}
|
||||
|
||||
void makeUnique()
|
||||
{
|
||||
if (mPointer.notNull() && mPointer.get()->getNumRefs() > 1)
|
||||
{
|
||||
mPointer = new Type(*mPointer.get());
|
||||
}
|
||||
}
|
||||
|
||||
operator BOOL() const { return (BOOL)mPointer; }
|
||||
operator bool() const { return (bool)mPointer; }
|
||||
bool operator!() const { return !mPointer; }
|
||||
bool isNull() const { return mPointer.isNull(); }
|
||||
bool notNull() const { return mPointer.notNull(); }
|
||||
|
||||
bool operator !=(Type* ptr) const { return (mPointer.get() != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer.get() == ptr); }
|
||||
bool operator ==(const LLCopyOnWritePointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLCopyOnWritePointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLCopyOnWritePointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
operator const Type*() const { return mPointer.get(); }
|
||||
const Type* operator->() const { return mPointer.get(); }
|
||||
protected:
|
||||
LLPointer<Type> mPointer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @file llpredicate.cpp
|
||||
* @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llpredicate.h"
|
||||
|
||||
namespace LLPredicate
|
||||
{
|
||||
const U32 cPredicateFlagsFromEnum[5] =
|
||||
{
|
||||
0xAAAAaaaa, // 10101010101010101010101010101010
|
||||
0xCCCCcccc, // 11001100110011001100110011001100
|
||||
0xF0F0F0F0, // 11110000111100001111000011110000
|
||||
0xFF00FF00, // 11111111000000001111111100000000
|
||||
0xFFFF0000 // 11111111111111110000000000000000
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
/**
|
||||
* @file llpredicate.h
|
||||
* @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLPREDICATE_H
|
||||
#define LL_LLPREDICATE_H
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
namespace LLPredicate
|
||||
{
|
||||
template<typename ENUM> class Rule;
|
||||
|
||||
extern const U32 cPredicateFlagsFromEnum[5];
|
||||
|
||||
template<typename ENUM>
|
||||
class Value
|
||||
{
|
||||
public:
|
||||
typedef U32 predicate_flag_t;
|
||||
static const S32 cMaxEnum = 5;
|
||||
|
||||
Value(ENUM e, bool predicate_value = true)
|
||||
: mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e])
|
||||
{
|
||||
llassert(0 <= e && e < cMaxEnum);
|
||||
}
|
||||
|
||||
Value()
|
||||
: mPredicateFlags(0xFFFFffff)
|
||||
{}
|
||||
|
||||
Value operator!() const
|
||||
{
|
||||
Value new_value;
|
||||
new_value.mPredicateFlags = ~mPredicateFlags;
|
||||
return new_value;
|
||||
}
|
||||
|
||||
Value operator &&(const Value other) const
|
||||
{
|
||||
Value new_value;
|
||||
new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags;
|
||||
return new_value;
|
||||
}
|
||||
|
||||
Value operator ||(const Value other) const
|
||||
{
|
||||
Value new_value;
|
||||
new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags;
|
||||
return new_value;
|
||||
}
|
||||
|
||||
void set(ENUM e, bool value = true)
|
||||
{
|
||||
llassert(0 <= e && e < cMaxEnum);
|
||||
predicate_flag_t flags_to_modify;
|
||||
predicate_flag_t mask = cPredicateFlagsFromEnum[e];
|
||||
if (value)
|
||||
{ // add predicate "e" to flags that don't contain it already
|
||||
flags_to_modify = (mPredicateFlags & ~mask);
|
||||
// clear flags not containing e
|
||||
mPredicateFlags &= mask;
|
||||
// add back flags shifted to contain e
|
||||
mPredicateFlags |= flags_to_modify << (0x1 << e);
|
||||
}
|
||||
else
|
||||
{ // remove predicate "e" from flags that contain it
|
||||
flags_to_modify = (mPredicateFlags & mask);
|
||||
// clear flags containing e
|
||||
mPredicateFlags &= ~mask;
|
||||
// add back flags shifted to not contain e
|
||||
mPredicateFlags |= flags_to_modify >> (0x1 << e);
|
||||
}
|
||||
}
|
||||
|
||||
void forget(ENUM e)
|
||||
{
|
||||
set(e, true);
|
||||
U32 flags_with_predicate = mPredicateFlags;
|
||||
set(e, false);
|
||||
// ambiguous value is result of adding and removing predicate at the same time!
|
||||
mPredicateFlags |= flags_with_predicate;
|
||||
}
|
||||
|
||||
bool allSet() const
|
||||
{
|
||||
return mPredicateFlags == ~0;
|
||||
}
|
||||
|
||||
bool noneSet() const
|
||||
{
|
||||
return mPredicateFlags == 0;
|
||||
}
|
||||
|
||||
bool someSet() const
|
||||
{
|
||||
return mPredicateFlags != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
predicate_flag_t mPredicateFlags;
|
||||
};
|
||||
|
||||
template<typename ENUM>
|
||||
class Rule
|
||||
{
|
||||
public:
|
||||
Rule(ENUM value)
|
||||
: mRule(value)
|
||||
{}
|
||||
|
||||
Rule(const Value<ENUM> other)
|
||||
: mRule(other)
|
||||
{}
|
||||
|
||||
Rule()
|
||||
{}
|
||||
|
||||
void require(ENUM e)
|
||||
{
|
||||
mRule.set(e, require);
|
||||
}
|
||||
|
||||
void allow(ENUM e)
|
||||
{
|
||||
mRule.forget(e);
|
||||
}
|
||||
|
||||
bool check(const Value<ENUM> value) const
|
||||
{
|
||||
return (mRule && value).someSet();
|
||||
}
|
||||
|
||||
bool requires(const Value<ENUM> value) const
|
||||
{
|
||||
return (mRule && value).someSet() && (!mRule && value).noneSet();
|
||||
}
|
||||
|
||||
bool isAmbivalent(const Value<ENUM> value) const
|
||||
{
|
||||
return (mRule && value).someSet() && (!mRule && value).someSet();
|
||||
}
|
||||
|
||||
bool acceptsAll() const
|
||||
{
|
||||
return mRule.allSet();
|
||||
}
|
||||
|
||||
bool acceptsNone() const
|
||||
{
|
||||
return mRule.noneSet();
|
||||
}
|
||||
|
||||
Rule operator!() const
|
||||
{
|
||||
Rule new_rule;
|
||||
new_rule.mRule = !mRule;
|
||||
return new_rule;
|
||||
}
|
||||
|
||||
Rule operator &&(const Rule other) const
|
||||
{
|
||||
Rule new_rule;
|
||||
new_rule.mRule = mRule && other.mRule;
|
||||
return new_rule;
|
||||
}
|
||||
|
||||
Rule operator ||(const Rule other) const
|
||||
{
|
||||
Rule new_rule;
|
||||
new_rule.mRule = mRule || other.mRule;
|
||||
return new_rule;
|
||||
}
|
||||
|
||||
private:
|
||||
Value<ENUM> mRule;
|
||||
};
|
||||
}
|
||||
|
||||
template<typename ENUM>
|
||||
LLPredicate::Value<ENUM> ll_make_predicate(ENUM e, bool predicate_value = true)
|
||||
{
|
||||
return LLPredicate::Value<ENUM>(e, predicate_value);
|
||||
}
|
||||
|
||||
|
||||
#endif // LL_LLPREDICATE_H
|
||||
|
|
@ -38,8 +38,7 @@
|
|||
#include <stdexcept>
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h> // HANDLE (eye roll)
|
||||
#include "llwin32headerslean.h" // for HANDLE
|
||||
#elif LL_LINUX
|
||||
#if defined(Status)
|
||||
#undef Status
|
||||
|
|
|
|||
|
|
@ -32,9 +32,7 @@
|
|||
//#include <memory>
|
||||
|
||||
#if LL_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include "llwin32headerslean.h"
|
||||
# define _interlockedbittestandset _renamed_interlockedbittestandset
|
||||
# define _interlockedbittestandreset _renamed_interlockedbittestandreset
|
||||
# include <intrin.h>
|
||||
|
|
@ -877,7 +875,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL)
|
|||
|
||||
|
||||
LLProcessorInfo::~LLProcessorInfo() {}
|
||||
F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
|
||||
LLUnitImplicit<LLUnits::Megahertz, F64> LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
|
||||
bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
|
||||
bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
|
||||
bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#ifndef LLPROCESSOR_H
|
||||
#define LLPROCESSOR_H
|
||||
#include "llunit.h"
|
||||
|
||||
class LLProcessorInfoImpl;
|
||||
|
||||
class LL_COMMON_API LLProcessorInfo
|
||||
|
|
@ -35,7 +37,7 @@ public:
|
|||
LLProcessorInfo();
|
||||
~LLProcessorInfo();
|
||||
|
||||
F64 getCPUFrequency() const;
|
||||
LLUnitImplicit<LLUnits::Megahertz, F64> getCPUFrequency() const;
|
||||
bool hasSSE() const;
|
||||
bool hasSSE2() const;
|
||||
bool hasAltivec() const;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h" // ms_sleep()
|
||||
#include "lltracethreadrecorder.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
|
@ -134,8 +135,8 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms)
|
|||
pending = getPending();
|
||||
if(pending > 0)
|
||||
{
|
||||
unpause();
|
||||
}
|
||||
unpause();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -508,6 +509,9 @@ void LLQueuedThread::run()
|
|||
threadedUpdate();
|
||||
|
||||
int res = processNextRequest();
|
||||
|
||||
LLTrace::get_thread_recorder()->pushToMaster();
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
mIdleThread = TRUE;
|
||||
|
|
|
|||
|
|
@ -102,13 +102,13 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool
|
|||
//readSDValues(sd, block);
|
||||
}
|
||||
|
||||
void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block)
|
||||
void LLParamSDParser::writeSDImpl(LLSD& sd, const LLInitParam::BaseBlock& block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block)
|
||||
{
|
||||
mNameStack.clear();
|
||||
mWriteRootSD = &sd;
|
||||
|
||||
name_stack_t name_stack;
|
||||
block.serializeBlock(*this, name_stack);
|
||||
block.serializeBlock(*this, name_stack, rules, diff_block);
|
||||
}
|
||||
|
||||
/*virtual*/ std::string LLParamSDParser::getCurrentElementName()
|
||||
|
|
@ -223,10 +223,14 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
|
|||
{
|
||||
bool new_traversal = it->second;
|
||||
|
||||
LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first];
|
||||
|
||||
if (child_sd->isArray())
|
||||
LLSD* child_sd;
|
||||
if (it->first.empty())
|
||||
{
|
||||
child_sd = sd_to_write;
|
||||
if (child_sd->isUndefined())
|
||||
{
|
||||
*child_sd = LLSD::emptyArray();
|
||||
}
|
||||
if (new_traversal)
|
||||
{
|
||||
// write to new element at end
|
||||
|
|
@ -240,22 +244,7 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:
|
|||
}
|
||||
else
|
||||
{
|
||||
if (new_traversal
|
||||
&& child_sd->isDefined()
|
||||
&& !child_sd->isArray())
|
||||
{
|
||||
// copy child contents into first element of an array
|
||||
LLSD new_array = LLSD::emptyArray();
|
||||
new_array.append(*child_sd);
|
||||
// assign array to slot that previously held the single value
|
||||
*child_sd = new_array;
|
||||
// return next element in that array
|
||||
sd_to_write = &((*child_sd)[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sd_to_write = child_sd;
|
||||
}
|
||||
sd_to_write = &(*sd_to_write)[it->first];
|
||||
}
|
||||
it->second = false;
|
||||
}
|
||||
|
|
@ -283,8 +272,9 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI
|
|||
it != sd.endArray();
|
||||
++it)
|
||||
{
|
||||
stack.back().second = true;
|
||||
stack.push_back(make_pair(std::string(), true));
|
||||
readSDValues(cb, *it, stack);
|
||||
stack.pop_back();
|
||||
}
|
||||
}
|
||||
else if (sd.isUndefined())
|
||||
|
|
@ -315,6 +305,12 @@ namespace LLInitParam
|
|||
// block param interface
|
||||
bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name)
|
||||
{
|
||||
if (name_stack.first == name_stack.second
|
||||
&& p.readValue<LLSD>(mValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack);
|
||||
|
||||
LLSD::String string;
|
||||
|
|
@ -333,10 +329,14 @@ namespace LLInitParam
|
|||
p.writeValue<LLSD::String>(sd.asString(), name_stack);
|
||||
}
|
||||
|
||||
void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
|
||||
bool ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const
|
||||
{
|
||||
// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
|
||||
Parser::name_stack_t stack;
|
||||
LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack);
|
||||
// attempt to write LLSD out directly
|
||||
if (!p.writeValue<LLSD>(mValue, name_stack))
|
||||
{
|
||||
// otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc)
|
||||
LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "llinitparam.h"
|
||||
#include "boost/function.hpp"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
struct LL_COMMON_API LLParamSDParserUtilities
|
||||
{
|
||||
|
|
@ -50,11 +51,28 @@ typedef LLInitParam::Parser parser_t;
|
|||
public:
|
||||
LLParamSDParser();
|
||||
void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false);
|
||||
void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block);
|
||||
template<typename BLOCK>
|
||||
void writeSD(LLSD& sd,
|
||||
const BLOCK& block,
|
||||
const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(),
|
||||
const LLInitParam::BaseBlock* diff_block = NULL)
|
||||
{
|
||||
if (!diff_block
|
||||
&& !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE))
|
||||
{
|
||||
diff_block = &LLInitParam::defaultValue<BLOCK>();
|
||||
}
|
||||
writeSDImpl(sd, block, rules, diff_block);
|
||||
}
|
||||
|
||||
/*virtual*/ std::string getCurrentElementName();
|
||||
|
||||
private:
|
||||
void writeSDImpl(LLSD& sd,
|
||||
const LLInitParam::BaseBlock& block,
|
||||
const LLInitParam::predicate_rule_t,
|
||||
const LLInitParam::BaseBlock* diff_block);
|
||||
|
||||
void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack);
|
||||
|
||||
template<typename T>
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ template <typename DERIVED_TYPE>
|
|||
class LLSingleton : private boost::noncopyable
|
||||
{
|
||||
|
||||
private:
|
||||
protected:
|
||||
typedef enum e_init_state
|
||||
{
|
||||
UNINITIALIZED,
|
||||
|
|
@ -124,7 +124,7 @@ private:
|
|||
public:
|
||||
virtual ~LLSingleton()
|
||||
{
|
||||
SingletonInstanceData& data = getData();
|
||||
SingletonInstanceData& data = getSingletonData();
|
||||
data.mSingletonInstance = NULL;
|
||||
data.mInitState = DELETED;
|
||||
}
|
||||
|
|
@ -151,29 +151,15 @@ public:
|
|||
*/
|
||||
static void deleteSingleton()
|
||||
{
|
||||
delete getData().mSingletonInstance;
|
||||
getData().mSingletonInstance = NULL;
|
||||
getData().mInitState = DELETED;
|
||||
}
|
||||
|
||||
static SingletonInstanceData& getData()
|
||||
{
|
||||
// this is static to cache the lookup results
|
||||
static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
|
||||
|
||||
// *TODO - look into making this threadsafe
|
||||
if(NULL == registry)
|
||||
{
|
||||
static SingletonInstanceData data;
|
||||
registry = &data;
|
||||
}
|
||||
|
||||
return *static_cast<SingletonInstanceData *>(registry);
|
||||
SingletonInstanceData& data = getSingletonData();
|
||||
delete data.mSingletonInstance;
|
||||
data.mSingletonInstance = NULL;
|
||||
data.mInitState = DELETED;
|
||||
}
|
||||
|
||||
static DERIVED_TYPE* getInstance()
|
||||
{
|
||||
SingletonInstanceData& data = getData();
|
||||
SingletonInstanceData& data = getSingletonData();
|
||||
|
||||
if (data.mInitState == CONSTRUCTING)
|
||||
{
|
||||
|
|
@ -197,6 +183,12 @@ public:
|
|||
return data.mSingletonInstance;
|
||||
}
|
||||
|
||||
static DERIVED_TYPE* getIfExists()
|
||||
{
|
||||
SingletonInstanceData& data = getSingletonData();
|
||||
return data.mSingletonInstance;
|
||||
}
|
||||
|
||||
// Reference version of getInstance()
|
||||
// Preferred over getInstance() as it disallows checking for NULL
|
||||
static DERIVED_TYPE& instance()
|
||||
|
|
@ -208,17 +200,31 @@ public:
|
|||
// Use this to avoid accessing singletons before the can safely be constructed
|
||||
static bool instanceExists()
|
||||
{
|
||||
return getData().mInitState == INITIALIZED;
|
||||
return getSingletonData().mInitState == INITIALIZED;
|
||||
}
|
||||
|
||||
// Has this singleton already been deleted?
|
||||
// Use this to avoid accessing singletons from a static object's destructor
|
||||
static bool destroyed()
|
||||
{
|
||||
return getData().mInitState == DELETED;
|
||||
return getSingletonData().mInitState == DELETED;
|
||||
}
|
||||
|
||||
private:
|
||||
static SingletonInstanceData& getSingletonData()
|
||||
{
|
||||
// this is static to cache the lookup results
|
||||
static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
|
||||
|
||||
// *TODO - look into making this threadsafe
|
||||
if(NULL == registry)
|
||||
{
|
||||
static SingletonInstanceData data;
|
||||
registry = &data;
|
||||
}
|
||||
|
||||
return *static_cast<SingletonInstanceData *>(registry);
|
||||
}
|
||||
virtual void initSingleton() {}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -210,8 +210,7 @@ inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap()
|
|||
: mInsertFirst(NULL),
|
||||
mEquals(defaultEquals)
|
||||
{
|
||||
// Skipmaps must have binary depth of at least 2
|
||||
cassert(BINARY_DEPTH >= 2);
|
||||
llstatic_assert(BINARY_DEPTH >= 2, "Skipmaps must have binary depth of at least 2");
|
||||
|
||||
S32 i;
|
||||
for (i = 0; i < BINARY_DEPTH; i++)
|
||||
|
|
@ -229,8 +228,7 @@ inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap(BOOL (*insert_f
|
|||
: mInsertFirst(insert_first),
|
||||
mEquals(equals)
|
||||
{
|
||||
// Skipmaps must have binary depth of at least 2
|
||||
cassert(BINARY_DEPTH >= 2);
|
||||
llstatic_assert(BINARY_DEPTH >= 2, "Skipmaps must have binary depth of at least 2");
|
||||
|
||||
mLevel = 1;
|
||||
S32 i;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "windows.h"
|
||||
#include "llwin32headerslean.h"
|
||||
#include "Dbghelp.h"
|
||||
|
||||
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
|
||||
|
|
|
|||
|
|
@ -1,404 +0,0 @@
|
|||
/**
|
||||
* @file llstat.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llstat.h"
|
||||
#include "lllivefile.h"
|
||||
#include "llerrorcontrol.h"
|
||||
#include "llframetimer.h"
|
||||
#include "timing.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llstl.h"
|
||||
#include "u64.h"
|
||||
|
||||
|
||||
// statics
|
||||
//------------------------------------------------------------------------
|
||||
LLTimer LLStat::sTimer;
|
||||
LLFrameTimer LLStat::sFrameTimer;
|
||||
|
||||
void LLStat::reset()
|
||||
{
|
||||
mNumValues = 0;
|
||||
mLastValue = 0.f;
|
||||
delete[] mBins;
|
||||
mBins = new ValueEntry[mNumBins];
|
||||
mCurBin = mNumBins-1;
|
||||
mNextBin = 0;
|
||||
}
|
||||
|
||||
LLStat::LLStat(std::string name, S32 num_bins, BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins),
|
||||
mName(name),
|
||||
mBins(NULL)
|
||||
{
|
||||
llassert(mNumBins > 0);
|
||||
mLastTime = 0.f;
|
||||
|
||||
reset();
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
stat_map_t::iterator iter = getStatList().find(mName);
|
||||
if (iter != getStatList().end())
|
||||
llwarns << "LLStat with duplicate name: " << mName << llendl;
|
||||
getStatList().insert(std::make_pair(mName, this));
|
||||
}
|
||||
}
|
||||
|
||||
LLStat::stat_map_t& LLStat::getStatList()
|
||||
{
|
||||
static LLStat::stat_map_t stat_list;
|
||||
return stat_list;
|
||||
}
|
||||
|
||||
|
||||
LLStat::~LLStat()
|
||||
{
|
||||
delete[] mBins;
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
// handle multiple entries with the same name
|
||||
stat_map_t::iterator iter = getStatList().find(mName);
|
||||
while (iter != getStatList().end() && iter->second != this)
|
||||
++iter;
|
||||
getStatList().erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void LLStat::start()
|
||||
{
|
||||
if (mUseFrameTimer)
|
||||
{
|
||||
mBins[mNextBin].mBeginTime = sFrameTimer.getElapsedSeconds();
|
||||
}
|
||||
else
|
||||
{
|
||||
mBins[mNextBin].mBeginTime = sTimer.getElapsedTimeF64();
|
||||
}
|
||||
}
|
||||
|
||||
void LLStat::addValue(const F32 value)
|
||||
{
|
||||
if (mNumValues < mNumBins)
|
||||
{
|
||||
mNumValues++;
|
||||
}
|
||||
|
||||
// Increment the bin counters.
|
||||
mCurBin++;
|
||||
if (mCurBin >= mNumBins)
|
||||
{
|
||||
mCurBin = 0;
|
||||
}
|
||||
mNextBin++;
|
||||
if (mNextBin >= mNumBins)
|
||||
{
|
||||
mNextBin = 0;
|
||||
}
|
||||
|
||||
mBins[mCurBin].mValue = value;
|
||||
if (mUseFrameTimer)
|
||||
{
|
||||
mBins[mCurBin].mTime = sFrameTimer.getElapsedSeconds();
|
||||
}
|
||||
else
|
||||
{
|
||||
mBins[mCurBin].mTime = sTimer.getElapsedTimeF64();
|
||||
}
|
||||
mBins[mCurBin].mDT = (F32)(mBins[mCurBin].mTime - mBins[mCurBin].mBeginTime);
|
||||
|
||||
//this value is used to prime the min/max calls
|
||||
mLastTime = mBins[mCurBin].mTime;
|
||||
mLastValue = value;
|
||||
|
||||
// Set the begin time for the next stat segment.
|
||||
mBins[mNextBin].mBeginTime = mBins[mCurBin].mTime;
|
||||
mBins[mNextBin].mTime = mBins[mCurBin].mTime;
|
||||
mBins[mNextBin].mDT = 0.f;
|
||||
}
|
||||
|
||||
|
||||
F32 LLStat::getMax() const
|
||||
{
|
||||
S32 i;
|
||||
F32 current_max = mLastValue;
|
||||
if (mNumBins == 0)
|
||||
{
|
||||
current_max = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
|
||||
{
|
||||
// Skip the bin we're currently filling.
|
||||
if (i == mNextBin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (mBins[i].mValue > current_max)
|
||||
{
|
||||
current_max = mBins[i].mValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return current_max;
|
||||
}
|
||||
|
||||
F32 LLStat::getMean() const
|
||||
{
|
||||
S32 i;
|
||||
F32 current_mean = 0.f;
|
||||
S32 samples = 0;
|
||||
for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
|
||||
{
|
||||
// Skip the bin we're currently filling.
|
||||
if (i == mNextBin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
current_mean += mBins[i].mValue;
|
||||
samples++;
|
||||
}
|
||||
|
||||
// There will be a wrap error at 2^32. :)
|
||||
if (samples != 0)
|
||||
{
|
||||
current_mean /= samples;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_mean = 0.f;
|
||||
}
|
||||
return current_mean;
|
||||
}
|
||||
|
||||
F32 LLStat::getMin() const
|
||||
{
|
||||
S32 i;
|
||||
F32 current_min = mLastValue;
|
||||
|
||||
if (mNumBins == 0)
|
||||
{
|
||||
current_min = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
|
||||
{
|
||||
// Skip the bin we're currently filling.
|
||||
if (i == mNextBin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (mBins[i].mValue < current_min)
|
||||
{
|
||||
current_min = mBins[i].mValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return current_min;
|
||||
}
|
||||
|
||||
F32 LLStat::getPrev(S32 age) const
|
||||
{
|
||||
S32 bin;
|
||||
bin = mCurBin - age;
|
||||
|
||||
while (bin < 0)
|
||||
{
|
||||
bin += mNumBins;
|
||||
}
|
||||
|
||||
if (bin == mNextBin)
|
||||
{
|
||||
// Bogus for bin we're currently working on.
|
||||
return 0.f;
|
||||
}
|
||||
return mBins[bin].mValue;
|
||||
}
|
||||
|
||||
F32 LLStat::getPrevPerSec(S32 age) const
|
||||
{
|
||||
S32 bin;
|
||||
bin = mCurBin - age;
|
||||
|
||||
while (bin < 0)
|
||||
{
|
||||
bin += mNumBins;
|
||||
}
|
||||
|
||||
if (bin == mNextBin)
|
||||
{
|
||||
// Bogus for bin we're currently working on.
|
||||
return 0.f;
|
||||
}
|
||||
return mBins[bin].mValue / mBins[bin].mDT;
|
||||
}
|
||||
|
||||
F32 LLStat::getCurrent() const
|
||||
{
|
||||
return mBins[mCurBin].mValue;
|
||||
}
|
||||
|
||||
F32 LLStat::getCurrentPerSec() const
|
||||
{
|
||||
return mBins[mCurBin].mValue / mBins[mCurBin].mDT;
|
||||
}
|
||||
|
||||
F32 LLStat::getMeanPerSec() const
|
||||
{
|
||||
S32 i;
|
||||
F32 value = 0.f;
|
||||
F32 dt = 0.f;
|
||||
|
||||
for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
|
||||
{
|
||||
// Skip the bin we're currently filling.
|
||||
if (i == mNextBin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
value += mBins[i].mValue;
|
||||
dt += mBins[i].mDT;
|
||||
}
|
||||
|
||||
if (dt > 0.f)
|
||||
{
|
||||
return value/dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
F32 LLStat::getMeanDuration() const
|
||||
{
|
||||
F32 dur = 0.0f;
|
||||
S32 count = 0;
|
||||
for (S32 i=0; (i < mNumBins) && (i < mNumValues); i++)
|
||||
{
|
||||
if (i == mNextBin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
dur += mBins[i].mDT;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
dur /= F32(count);
|
||||
return dur;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
F32 LLStat::getMaxPerSec() const
|
||||
{
|
||||
F32 value;
|
||||
|
||||
if (mNextBin != 0)
|
||||
{
|
||||
value = mBins[0].mValue/mBins[0].mDT;
|
||||
}
|
||||
else if (mNumValues > 0)
|
||||
{
|
||||
value = mBins[1].mValue/mBins[1].mDT;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0.f;
|
||||
}
|
||||
|
||||
for (S32 i = 0; (i < mNumBins) && (i < mNumValues); i++)
|
||||
{
|
||||
// Skip the bin we're currently filling.
|
||||
if (i == mNextBin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
value = llmax(value, mBins[i].mValue/mBins[i].mDT);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
F32 LLStat::getMinPerSec() const
|
||||
{
|
||||
S32 i;
|
||||
F32 value;
|
||||
|
||||
if (mNextBin != 0)
|
||||
{
|
||||
value = mBins[0].mValue/mBins[0].mDT;
|
||||
}
|
||||
else if (mNumValues > 0)
|
||||
{
|
||||
value = mBins[1].mValue/mBins[0].mDT;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0.f;
|
||||
}
|
||||
|
||||
for (i = 0; (i < mNumBins) && (i < mNumValues); i++)
|
||||
{
|
||||
// Skip the bin we're currently filling.
|
||||
if (i == mNextBin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
value = llmin(value, mBins[i].mValue/mBins[i].mDT);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
U32 LLStat::getNumValues() const
|
||||
{
|
||||
return mNumValues;
|
||||
}
|
||||
|
||||
S32 LLStat::getNumBins() const
|
||||
{
|
||||
return mNumBins;
|
||||
}
|
||||
|
||||
S32 LLStat::getNextBin() const
|
||||
{
|
||||
return mNextBin;
|
||||
}
|
||||
|
||||
F64 LLStat::getLastTime() const
|
||||
{
|
||||
return mLastTime;
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
/**
|
||||
* @file llstat.h
|
||||
* @brief Runtime statistics accumulation.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLSTAT_H
|
||||
#define LL_LLSTAT_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "lltimer.h"
|
||||
#include "llframetimer.h"
|
||||
|
||||
class LLSD;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
class LL_COMMON_API LLStat
|
||||
{
|
||||
private:
|
||||
typedef std::multimap<std::string, LLStat*> stat_map_t;
|
||||
|
||||
static stat_map_t& getStatList();
|
||||
|
||||
public:
|
||||
LLStat(std::string name = std::string(), S32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
~LLStat();
|
||||
|
||||
void start(); // Start the timer for the current "frame", otherwise uses the time tracked from
|
||||
// the last addValue
|
||||
void reset();
|
||||
void addValue(const F32 value = 1.f); // Adds the current value being tracked, and tracks the DT.
|
||||
void addValue(const S32 value) { addValue((F32)value); }
|
||||
void addValue(const U32 value) { addValue((F32)value); }
|
||||
|
||||
S32 getNextBin() const;
|
||||
|
||||
F32 getPrev(S32 age) const; // Age is how many "addValues" previously - zero is current
|
||||
F32 getPrevPerSec(S32 age) const; // Age is how many "addValues" previously - zero is current
|
||||
F32 getCurrent() const;
|
||||
F32 getCurrentPerSec() const;
|
||||
|
||||
F32 getMin() const;
|
||||
F32 getMinPerSec() const;
|
||||
F32 getMean() const;
|
||||
F32 getMeanPerSec() const;
|
||||
F32 getMeanDuration() const;
|
||||
F32 getMax() const;
|
||||
F32 getMaxPerSec() const;
|
||||
|
||||
U32 getNumValues() const;
|
||||
S32 getNumBins() const;
|
||||
|
||||
F64 getLastTime() const;
|
||||
private:
|
||||
BOOL mUseFrameTimer;
|
||||
U32 mNumValues;
|
||||
U32 mNumBins;
|
||||
F32 mLastValue;
|
||||
F64 mLastTime;
|
||||
|
||||
struct ValueEntry
|
||||
{
|
||||
ValueEntry()
|
||||
: mValue(0.f),
|
||||
mBeginTime(0.0),
|
||||
mTime(0.0),
|
||||
mDT(0.f)
|
||||
{}
|
||||
F32 mValue;
|
||||
F64 mBeginTime;
|
||||
F64 mTime;
|
||||
F32 mDT;
|
||||
};
|
||||
ValueEntry* mBins;
|
||||
S32 mCurBin;
|
||||
S32 mNextBin;
|
||||
|
||||
std::string mName;
|
||||
|
||||
static LLTimer sTimer;
|
||||
static LLFrameTimer sFrameTimer;
|
||||
|
||||
public:
|
||||
static LLStat* getStat(const std::string& name)
|
||||
{
|
||||
// return the first stat that matches 'name'
|
||||
stat_map_t::iterator iter = getStatList().find(name);
|
||||
if (iter != getStatList().end())
|
||||
return iter->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LL_STAT_
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
#ifndef LL_LLSTATENUMS_H
|
||||
#define LL_LLSTATENUMS_H
|
||||
|
||||
enum
|
||||
enum ESimStatID
|
||||
{
|
||||
LL_SIM_STAT_TIME_DILATION = 0,
|
||||
LL_SIM_STAT_FPS = 1,
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
#include <typeinfo>
|
||||
|
|
|
|||
|
|
@ -28,11 +28,10 @@
|
|||
|
||||
#include "llstring.h"
|
||||
#include "llerror.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include "llwin32headerslean.h"
|
||||
#include <winnls.h> // for WideCharToMultiByte
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@
|
|||
#include <cstdio>
|
||||
#include <locale>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include "llsd.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llformat.h"
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
#include <wctype.h>
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "llprocessor.h"
|
||||
#include "llerrorcontrol.h"
|
||||
#include "llevents.h"
|
||||
#include "llformat.h"
|
||||
#include "lltimer.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil.h"
|
||||
|
|
@ -58,9 +59,7 @@
|
|||
using namespace llsd;
|
||||
|
||||
#if LL_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include "llwin32headerslean.h"
|
||||
# include <psapi.h> // GetPerformanceInfo() et al.
|
||||
#elif LL_DARWIN
|
||||
# include <errno.h>
|
||||
|
|
|
|||
|
|
@ -29,8 +29,11 @@
|
|||
#include "apr_portable.h"
|
||||
|
||||
#include "llthread.h"
|
||||
#include "llmutex.h"
|
||||
|
||||
#include "lltimer.h"
|
||||
#include "lltrace.h"
|
||||
#include "lltracethreadrecorder.h"
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
#include <sched.h>
|
||||
|
|
@ -56,12 +59,17 @@
|
|||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !LL_DARWIN
|
||||
U32 ll_thread_local sThreadID = 0;
|
||||
#if LL_DARWIN
|
||||
// statically allocated thread local storage not supported in Darwin executable formats
|
||||
#elif LL_WINDOWS
|
||||
U32 __declspec(thread) sThreadID = 0;
|
||||
#elif LL_LINUX
|
||||
U32 __thread sThreadID = 0;
|
||||
#endif
|
||||
|
||||
U32 LLThread::sIDIter = 0;
|
||||
|
||||
|
||||
LL_COMMON_API void assert_main_thread()
|
||||
{
|
||||
static U32 s_thread_id = LLThread::currentID();
|
||||
|
|
@ -85,6 +93,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
|||
{
|
||||
LLThread *threadp = (LLThread *)datap;
|
||||
|
||||
LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder();
|
||||
|
||||
#if !LL_DARWIN
|
||||
sThreadID = threadp->mID;
|
||||
#endif
|
||||
|
|
@ -97,16 +107,18 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
|||
// We're done with the run function, this thread is done executing now.
|
||||
threadp->mStatus = STOPPED;
|
||||
|
||||
delete thread_recorder;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
|
||||
mPaused(FALSE),
|
||||
mName(name),
|
||||
mAPRThreadp(NULL),
|
||||
mStatus(STOPPED)
|
||||
{
|
||||
|
||||
mID = ++sIDIter;
|
||||
|
||||
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
|
||||
|
|
@ -152,7 +164,7 @@ void LLThread::shutdown()
|
|||
//llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
|
||||
// Now wait a bit for the thread to exit
|
||||
// It's unclear whether I should even bother doing this - this destructor
|
||||
// should netver get called unless we're already stopped, really...
|
||||
// should never get called unless we're already stopped, really...
|
||||
S32 counter = 0;
|
||||
const S32 MAX_WAIT = 600;
|
||||
while (counter < MAX_WAIT)
|
||||
|
|
@ -282,7 +294,13 @@ void LLThread::setQuitting()
|
|||
// static
|
||||
U32 LLThread::currentID()
|
||||
{
|
||||
#if LL_DARWIN
|
||||
// statically allocated thread local storage not supported in Darwin executable formats
|
||||
return (U32)apr_os_thread_current();
|
||||
#else
|
||||
return sThreadID;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
@ -315,155 +333,6 @@ void LLThread::wakeLocked()
|
|||
|
||||
//============================================================================
|
||||
|
||||
LLMutex::LLMutex(apr_pool_t *poolp) :
|
||||
mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
|
||||
{
|
||||
//if (poolp)
|
||||
//{
|
||||
// mIsLocalPool = FALSE;
|
||||
// mAPRPoolp = poolp;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
mIsLocalPool = TRUE;
|
||||
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
|
||||
}
|
||||
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
|
||||
}
|
||||
|
||||
|
||||
LLMutex::~LLMutex()
|
||||
{
|
||||
#if MUTEX_DEBUG
|
||||
//bad assertion, the subclass LLSignal might be "locked", and that's OK
|
||||
//llassert_always(!isLocked()); // better not be locked!
|
||||
#endif
|
||||
apr_thread_mutex_destroy(mAPRMutexp);
|
||||
mAPRMutexp = NULL;
|
||||
if (mIsLocalPool)
|
||||
{
|
||||
apr_pool_destroy(mAPRPoolp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLMutex::lock()
|
||||
{
|
||||
if(isSelfLocked())
|
||||
{ //redundant lock
|
||||
mCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
apr_thread_mutex_lock(mAPRMutexp);
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
// Have to have the lock before we can access the debug info
|
||||
U32 id = LLThread::currentID();
|
||||
if (mIsLocked[id] != FALSE)
|
||||
llerrs << "Already locked in Thread: " << id << llendl;
|
||||
mIsLocked[id] = TRUE;
|
||||
#endif
|
||||
|
||||
#if LL_DARWIN
|
||||
mLockingThread = LLThread::currentID();
|
||||
#else
|
||||
mLockingThread = sThreadID;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLMutex::unlock()
|
||||
{
|
||||
if (mCount > 0)
|
||||
{ //not the root unlock
|
||||
mCount--;
|
||||
return;
|
||||
}
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
// Access the debug info while we have the lock
|
||||
U32 id = LLThread::currentID();
|
||||
if (mIsLocked[id] != TRUE)
|
||||
llerrs << "Not locked in Thread: " << id << llendl;
|
||||
mIsLocked[id] = FALSE;
|
||||
#endif
|
||||
|
||||
mLockingThread = NO_THREAD;
|
||||
apr_thread_mutex_unlock(mAPRMutexp);
|
||||
}
|
||||
|
||||
bool LLMutex::isLocked()
|
||||
{
|
||||
apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
|
||||
if (APR_STATUS_IS_EBUSY(status))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
apr_thread_mutex_unlock(mAPRMutexp);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LLMutex::isSelfLocked()
|
||||
{
|
||||
#if LL_DARWIN
|
||||
return mLockingThread == LLThread::currentID();
|
||||
#else
|
||||
return mLockingThread == sThreadID;
|
||||
#endif
|
||||
}
|
||||
|
||||
U32 LLMutex::lockingThread() const
|
||||
{
|
||||
return mLockingThread;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
LLCondition::LLCondition(apr_pool_t *poolp) :
|
||||
LLMutex(poolp)
|
||||
{
|
||||
// base class (LLMutex) has already ensured that mAPRPoolp is set up.
|
||||
|
||||
apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
|
||||
}
|
||||
|
||||
|
||||
LLCondition::~LLCondition()
|
||||
{
|
||||
apr_thread_cond_destroy(mAPRCondp);
|
||||
mAPRCondp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLCondition::wait()
|
||||
{
|
||||
if (!isLocked())
|
||||
{ //mAPRMutexp MUST be locked before calling apr_thread_cond_wait
|
||||
apr_thread_mutex_lock(mAPRMutexp);
|
||||
#if MUTEX_DEBUG
|
||||
// avoid asserts on destruction in non-release builds
|
||||
U32 id = LLThread::currentID();
|
||||
mIsLocked[id] = TRUE;
|
||||
#endif
|
||||
}
|
||||
apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
|
||||
}
|
||||
|
||||
void LLCondition::signal()
|
||||
{
|
||||
apr_thread_cond_signal(mAPRCondp);
|
||||
}
|
||||
|
||||
void LLCondition::broadcast()
|
||||
{
|
||||
apr_thread_cond_broadcast(mAPRCondp);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//static
|
||||
|
|
@ -514,7 +383,6 @@ LLThreadSafeRefCount::~LLThreadSafeRefCount()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
LLResponder::~LLResponder()
|
||||
|
|
|
|||
|
|
@ -30,20 +30,14 @@
|
|||
#include "llapp.h"
|
||||
#include "llapr.h"
|
||||
#include "apr_thread_cond.h"
|
||||
#include "llmutex.h"
|
||||
|
||||
class LLThread;
|
||||
class LLMutex;
|
||||
class LLCondition;
|
||||
|
||||
#if LL_WINDOWS
|
||||
#define ll_thread_local __declspec(thread)
|
||||
#else
|
||||
#define ll_thread_local __thread
|
||||
#endif
|
||||
LL_COMMON_API void assert_main_thread();
|
||||
|
||||
class LL_COMMON_API LLThread
|
||||
{
|
||||
private:
|
||||
friend class LLMutex;
|
||||
static U32 sIDIter;
|
||||
|
||||
public:
|
||||
|
|
@ -101,7 +95,7 @@ private:
|
|||
|
||||
protected:
|
||||
std::string mName;
|
||||
LLCondition* mRunCondition;
|
||||
class LLCondition* mRunCondition;
|
||||
LLMutex* mDataLock;
|
||||
|
||||
apr_thread_t *mAPRThreadp;
|
||||
|
|
@ -139,75 +133,6 @@ protected:
|
|||
// mDataLock->unlock();
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
|
||||
|
||||
class LL_COMMON_API LLMutex
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
NO_THREAD = 0xFFFFFFFF
|
||||
} e_locking_thread;
|
||||
|
||||
LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
|
||||
virtual ~LLMutex();
|
||||
|
||||
void lock(); // blocks
|
||||
void unlock();
|
||||
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
|
||||
bool isSelfLocked(); //return true if locked in a same thread
|
||||
U32 lockingThread() const; //get ID of locking thread
|
||||
|
||||
protected:
|
||||
apr_thread_mutex_t *mAPRMutexp;
|
||||
mutable U32 mCount;
|
||||
mutable U32 mLockingThread;
|
||||
|
||||
apr_pool_t *mAPRPoolp;
|
||||
BOOL mIsLocalPool;
|
||||
|
||||
#if MUTEX_DEBUG
|
||||
std::map<U32, BOOL> mIsLocked;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Actually a condition/mutex pair (since each condition needs to be associated with a mutex).
|
||||
class LL_COMMON_API LLCondition : public LLMutex
|
||||
{
|
||||
public:
|
||||
LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well.
|
||||
~LLCondition();
|
||||
|
||||
void wait(); // blocks
|
||||
void signal();
|
||||
void broadcast();
|
||||
|
||||
protected:
|
||||
apr_thread_cond_t *mAPRCondp;
|
||||
};
|
||||
|
||||
class LLMutexLock
|
||||
{
|
||||
public:
|
||||
LLMutexLock(LLMutex* mutex)
|
||||
{
|
||||
mMutex = mutex;
|
||||
|
||||
if(mMutex)
|
||||
mMutex->lock();
|
||||
}
|
||||
~LLMutexLock()
|
||||
{
|
||||
if(mMutex)
|
||||
mMutex->unlock();
|
||||
}
|
||||
private:
|
||||
LLMutex* mMutex;
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
||||
void LLThread::lockData()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* @file llthreadlocalstorage.cpp
|
||||
* @author Richard
|
||||
* @date 2013-1-11
|
||||
* @brief implementation of thread local storage utility classes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llthreadlocalstorage.h"
|
||||
|
||||
//
|
||||
//LLThreadLocalPointerBase
|
||||
//
|
||||
bool LLThreadLocalPointerBase::sInitialized = false;
|
||||
|
||||
void LLThreadLocalPointerBase::set( void* value )
|
||||
{
|
||||
llassert(sInitialized && mThreadKey);
|
||||
|
||||
apr_status_t result = apr_threadkey_private_set((void*)value, mThreadKey);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to set thread local data" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
void LLThreadLocalPointerBase::initStorage( )
|
||||
{
|
||||
apr_status_t result = apr_threadkey_private_create(&mThreadKey, NULL, gAPRPoolp);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to allocate thread local data" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
void LLThreadLocalPointerBase::destroyStorage()
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
if (mThreadKey)
|
||||
{
|
||||
apr_status_t result = apr_threadkey_private_delete(mThreadKey);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to delete thread local data" << llendl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLThreadLocalPointerBase::initAllThreadLocalStorage()
|
||||
{
|
||||
if (!sInitialized)
|
||||
{
|
||||
for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
(*it).initStorage();
|
||||
}
|
||||
sInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void LLThreadLocalPointerBase::destroyAllThreadLocalStorage()
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
//for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
|
||||
// it != end_it;
|
||||
// ++it)
|
||||
//{
|
||||
// (*it).destroyStorage();
|
||||
//}
|
||||
sInitialized = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,370 @@
|
|||
/**
|
||||
* @file llthreadlocalstorage.h
|
||||
* @author Richard
|
||||
* @brief Class wrappers for thread local storage
|
||||
*
|
||||
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLTHREADLOCALSTORAGE_H
|
||||
#define LL_LLTHREADLOCALSTORAGE_H
|
||||
|
||||
#include "llinstancetracker.h"
|
||||
#include "llapr.h"
|
||||
|
||||
class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase>
|
||||
{
|
||||
public:
|
||||
LLThreadLocalPointerBase()
|
||||
: mThreadKey(NULL)
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
initStorage();
|
||||
}
|
||||
}
|
||||
|
||||
LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other)
|
||||
: mThreadKey(NULL)
|
||||
{
|
||||
if (sInitialized)
|
||||
{
|
||||
initStorage();
|
||||
}
|
||||
}
|
||||
|
||||
~LLThreadLocalPointerBase()
|
||||
{
|
||||
destroyStorage();
|
||||
}
|
||||
|
||||
static void initAllThreadLocalStorage();
|
||||
static void destroyAllThreadLocalStorage();
|
||||
|
||||
protected:
|
||||
void set(void* value);
|
||||
|
||||
LL_FORCE_INLINE void* get() const
|
||||
{
|
||||
// llassert(sInitialized);
|
||||
void* ptr;
|
||||
apr_status_t result =
|
||||
apr_threadkey_private_get(&ptr, mThreadKey);
|
||||
if (result != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(result);
|
||||
llerrs << "Failed to get thread local data" << llendl;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void initStorage();
|
||||
void destroyStorage();
|
||||
|
||||
protected:
|
||||
apr_threadkey_t* mThreadKey;
|
||||
static bool sInitialized;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LLThreadLocalPointer : public LLThreadLocalPointerBase
|
||||
{
|
||||
public:
|
||||
|
||||
LLThreadLocalPointer()
|
||||
{}
|
||||
|
||||
explicit LLThreadLocalPointer(T* value)
|
||||
{
|
||||
set(value);
|
||||
}
|
||||
|
||||
|
||||
LLThreadLocalPointer(const LLThreadLocalPointer<T>& other)
|
||||
: LLThreadLocalPointerBase(other)
|
||||
{
|
||||
set(other.get());
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE T* get() const
|
||||
{
|
||||
return (T*)LLThreadLocalPointerBase::get();
|
||||
}
|
||||
|
||||
T* operator -> () const
|
||||
{
|
||||
return (T*)get();
|
||||
}
|
||||
|
||||
T& operator*() const
|
||||
{
|
||||
return *(T*)get();
|
||||
}
|
||||
|
||||
LLThreadLocalPointer<T>& operator = (T* value)
|
||||
{
|
||||
set((void*)value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator ==(const T* other) const
|
||||
{
|
||||
if (!sInitialized) return false;
|
||||
return get() == other;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DERIVED_TYPE>
|
||||
class LLThreadLocalSingleton
|
||||
{
|
||||
typedef enum e_init_state
|
||||
{
|
||||
UNINITIALIZED = 0,
|
||||
CONSTRUCTING,
|
||||
INITIALIZING,
|
||||
INITIALIZED,
|
||||
DELETED
|
||||
} EInitState;
|
||||
|
||||
public:
|
||||
LLThreadLocalSingleton()
|
||||
{}
|
||||
|
||||
virtual ~LLThreadLocalSingleton()
|
||||
{
|
||||
#if LL_DARWIN
|
||||
pthread_setspecific(sInstanceKey, NULL);
|
||||
#else
|
||||
sInstance = NULL;
|
||||
#endif
|
||||
setInitState(DELETED);
|
||||
}
|
||||
|
||||
static void deleteSingleton()
|
||||
{
|
||||
delete getIfExists();
|
||||
}
|
||||
|
||||
static DERIVED_TYPE* getInstance()
|
||||
{
|
||||
EInitState init_state = getInitState();
|
||||
if (init_state == CONSTRUCTING)
|
||||
{
|
||||
llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
|
||||
}
|
||||
|
||||
if (init_state == DELETED)
|
||||
{
|
||||
llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
|
||||
}
|
||||
|
||||
#if LL_DARWIN
|
||||
createTLSInstance();
|
||||
#endif
|
||||
if (!getIfExists())
|
||||
{
|
||||
setInitState(CONSTRUCTING);
|
||||
DERIVED_TYPE* instancep = new DERIVED_TYPE();
|
||||
#if LL_DARWIN
|
||||
S32 result = pthread_setspecific(sInstanceKey, (void*)instancep);
|
||||
if (result != 0)
|
||||
{
|
||||
llerrs << "Could not set thread local storage" << llendl;
|
||||
}
|
||||
#else
|
||||
sInstance = instancep;
|
||||
#endif
|
||||
setInitState(INITIALIZING);
|
||||
instancep->initSingleton();
|
||||
setInitState(INITIALIZED);
|
||||
}
|
||||
|
||||
return getIfExists();
|
||||
}
|
||||
|
||||
static DERIVED_TYPE* getIfExists()
|
||||
{
|
||||
#if LL_DARWIN
|
||||
return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey);
|
||||
#else
|
||||
return sInstance;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reference version of getInstance()
|
||||
// Preferred over getInstance() as it disallows checking for NULL
|
||||
static DERIVED_TYPE& instance()
|
||||
{
|
||||
return *getInstance();
|
||||
}
|
||||
|
||||
// Has this singleton been created uet?
|
||||
// Use this to avoid accessing singletons before the can safely be constructed
|
||||
static bool instanceExists()
|
||||
{
|
||||
return getInitState() == INITIALIZED;
|
||||
}
|
||||
|
||||
// Has this singleton already been deleted?
|
||||
// Use this to avoid accessing singletons from a static object's destructor
|
||||
static bool destroyed()
|
||||
{
|
||||
return getInitState() == DELETED;
|
||||
}
|
||||
private:
|
||||
#if LL_DARWIN
|
||||
static void createTLSInitState()
|
||||
{
|
||||
static S32 key_created = pthread_key_create(&sInitStateKey, NULL);
|
||||
if (key_created != 0)
|
||||
{
|
||||
llerrs << "Could not create thread local storage" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
static void createTLSInstance()
|
||||
{
|
||||
static S32 key_created = pthread_key_create(&sInstanceKey, NULL);
|
||||
if (key_created != 0)
|
||||
{
|
||||
llerrs << "Could not create thread local storage" << llendl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
static EInitState getInitState()
|
||||
{
|
||||
#if LL_DARWIN
|
||||
createTLSInitState();
|
||||
return (EInitState)(int)pthread_getspecific(sInitStateKey);
|
||||
#else
|
||||
return sInitState;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void setInitState(EInitState state)
|
||||
{
|
||||
#if LL_DARWIN
|
||||
createTLSInitState();
|
||||
pthread_setspecific(sInitStateKey, (void*)state);
|
||||
#else
|
||||
sInitState = state;
|
||||
#endif
|
||||
}
|
||||
LLThreadLocalSingleton(const LLThreadLocalSingleton& other);
|
||||
virtual void initSingleton() {}
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
static __declspec(thread) DERIVED_TYPE* sInstance;
|
||||
static __declspec(thread) EInitState sInitState;
|
||||
#elif LL_LINUX
|
||||
static __thread DERIVED_TYPE* sInstance;
|
||||
static __thread EInitState sInitState;
|
||||
#elif LL_DARWIN
|
||||
static pthread_key_t sInstanceKey;
|
||||
static pthread_key_t sInitStateKey;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if LL_WINDOWS
|
||||
template<typename DERIVED_TYPE>
|
||||
__declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
|
||||
|
||||
template<typename DERIVED_TYPE>
|
||||
__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
|
||||
#elif LL_LINUX
|
||||
template<typename DERIVED_TYPE>
|
||||
__thread DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
|
||||
|
||||
template<typename DERIVED_TYPE>
|
||||
__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
|
||||
#elif LL_DARWIN
|
||||
template<typename DERIVED_TYPE>
|
||||
pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInstanceKey;
|
||||
|
||||
template<typename DERIVED_TYPE>
|
||||
pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInitStateKey;
|
||||
|
||||
#endif
|
||||
|
||||
template<typename DERIVED_TYPE>
|
||||
class LLThreadLocalSingletonPointer
|
||||
{
|
||||
public:
|
||||
void operator =(DERIVED_TYPE* value)
|
||||
{
|
||||
setInstance(value);
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE static DERIVED_TYPE* getInstance()
|
||||
{
|
||||
#if LL_DARWIN
|
||||
createTLSKey();
|
||||
return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey);
|
||||
#else
|
||||
return sInstance;
|
||||
#endif
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE static void setInstance(DERIVED_TYPE* instance)
|
||||
{
|
||||
#if LL_DARWIN
|
||||
createTLSKey();
|
||||
pthread_setspecific(sInstanceKey, (void*)instance);
|
||||
#else
|
||||
sInstance = instance;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#if LL_WINDOWS
|
||||
static __declspec(thread) DERIVED_TYPE* sInstance;
|
||||
#elif LL_LINUX
|
||||
static __thread DERIVED_TYPE* sInstance;
|
||||
#elif LL_DARWIN
|
||||
static void TLSError()
|
||||
{
|
||||
llerrs << "Could not create thread local storage" << llendl;
|
||||
}
|
||||
static void createTLSKey()
|
||||
{
|
||||
static S32 key_created = pthread_key_create(&sInstanceKey, NULL);
|
||||
if (key_created != 0)
|
||||
{
|
||||
llerrs << "Could not create thread local storage" << llendl;
|
||||
}
|
||||
}
|
||||
static pthread_key_t sInstanceKey;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if LL_WINDOWS
|
||||
template<typename DERIVED_TYPE>
|
||||
__declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL;
|
||||
#elif LL_LINUX
|
||||
template<typename DERIVED_TYPE>
|
||||
__thread DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL;
|
||||
#elif LL_DARWIN
|
||||
template<typename DERIVED_TYPE>
|
||||
pthread_key_t LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstanceKey;
|
||||
#endif
|
||||
|
||||
#endif // LL_LLTHREADLOCALSTORAGE_H
|
||||
|
|
@ -31,11 +31,9 @@
|
|||
#include "u64.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
# include "llwin32headerslean.h"
|
||||
#elif LL_LINUX || LL_SOLARIS || LL_DARWIN
|
||||
# include <errno.h>
|
||||
# include <errno.h>
|
||||
# include <sys/time.h>
|
||||
#else
|
||||
# error "architecture not supported"
|
||||
|
|
@ -287,14 +285,14 @@ LLTimer::~LLTimer()
|
|||
}
|
||||
|
||||
// static
|
||||
U64 LLTimer::getTotalTime()
|
||||
LLUnitImplicit<LLUnits::Microseconds, U64> LLTimer::getTotalTime()
|
||||
{
|
||||
// simply call into the implementation function.
|
||||
return totalTime();
|
||||
}
|
||||
|
||||
// static
|
||||
F64 LLTimer::getTotalSeconds()
|
||||
LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getTotalSeconds()
|
||||
{
|
||||
return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;
|
||||
}
|
||||
|
|
@ -343,23 +341,23 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount)
|
|||
}
|
||||
|
||||
|
||||
F64 LLTimer::getElapsedTimeF64() const
|
||||
LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeF64() const
|
||||
{
|
||||
U64 last = mLastClockCount;
|
||||
return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;
|
||||
}
|
||||
|
||||
F32 LLTimer::getElapsedTimeF32() const
|
||||
LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeF32() const
|
||||
{
|
||||
return (F32)getElapsedTimeF64();
|
||||
}
|
||||
|
||||
F64 LLTimer::getElapsedTimeAndResetF64()
|
||||
LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeAndResetF64()
|
||||
{
|
||||
return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;
|
||||
}
|
||||
|
||||
F32 LLTimer::getElapsedTimeAndResetF32()
|
||||
LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeAndResetF32()
|
||||
{
|
||||
return (F32)getElapsedTimeAndResetF64();
|
||||
}
|
||||
|
|
@ -372,7 +370,7 @@ void LLTimer::setTimerExpirySec(F32 expiration)
|
|||
+ (U64)((F32)(expiration * gClockFrequency));
|
||||
}
|
||||
|
||||
F32 LLTimer::getRemainingTimeF32() const
|
||||
LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getRemainingTimeF32() const
|
||||
{
|
||||
U64 cur_ticks = get_clock_count();
|
||||
if (cur_ticks > mExpirationTicks)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include <string>
|
||||
#include <list>
|
||||
// units conversions
|
||||
#include "llunit.h"
|
||||
#ifndef USEC_PER_SEC
|
||||
const U32 USEC_PER_SEC = 1000000;
|
||||
#endif
|
||||
|
|
@ -55,7 +56,7 @@ public:
|
|||
protected:
|
||||
U64 mLastClockCount;
|
||||
U64 mExpirationTicks;
|
||||
BOOL mStarted;
|
||||
bool mStarted;
|
||||
|
||||
public:
|
||||
LLTimer();
|
||||
|
|
@ -66,16 +67,16 @@ public:
|
|||
|
||||
// Return a high precision number of seconds since the start of
|
||||
// this application instance.
|
||||
static F64 getElapsedSeconds()
|
||||
static LLUnitImplicit<LLUnits::Seconds, F64> getElapsedSeconds()
|
||||
{
|
||||
return sTimer->getElapsedTimeF64();
|
||||
}
|
||||
|
||||
// Return a high precision usec since epoch
|
||||
static U64 getTotalTime();
|
||||
static LLUnitImplicit<LLUnits::Microseconds, U64> getTotalTime();
|
||||
|
||||
// Return a high precision seconds since epoch
|
||||
static F64 getTotalSeconds();
|
||||
static LLUnitImplicit<LLUnits::Seconds, F64> getTotalSeconds();
|
||||
|
||||
|
||||
// MANIPULATORS
|
||||
|
|
@ -86,18 +87,18 @@ public:
|
|||
void setTimerExpirySec(F32 expiration);
|
||||
BOOL checkExpirationAndReset(F32 expiration);
|
||||
BOOL hasExpired() const;
|
||||
F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
|
||||
F64 getElapsedTimeAndResetF64();
|
||||
LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
|
||||
LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeAndResetF64();
|
||||
|
||||
F32 getRemainingTimeF32() const;
|
||||
LLUnitImplicit<LLUnits::Seconds, F32> getRemainingTimeF32() const;
|
||||
|
||||
static BOOL knownBadTimer();
|
||||
|
||||
// ACCESSORS
|
||||
F32 getElapsedTimeF32() const; // Returns elapsed time in seconds
|
||||
F64 getElapsedTimeF64() const; // Returns elapsed time in seconds
|
||||
LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeF32() const; // Returns elapsed time in seconds
|
||||
LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeF64() const; // Returns elapsed time in seconds
|
||||
|
||||
BOOL getStarted() const { return mStarted; }
|
||||
bool getStarted() const { return mStarted; }
|
||||
|
||||
|
||||
static U64 getCurrentClockCount(); // Returns the raw clockticks
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* @file lltrace.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lltrace.h"
|
||||
#include "lltracerecording.h"
|
||||
#include "lltracethreadrecorder.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
static S32 sInitializationCount = 0;
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
|
||||
static MasterThreadRecorder* gMasterThreadRecorder = NULL;
|
||||
|
||||
void init()
|
||||
{
|
||||
if (sInitializationCount++ == 0)
|
||||
{
|
||||
gMasterThreadRecorder = new MasterThreadRecorder();
|
||||
}
|
||||
}
|
||||
|
||||
bool isInitialized()
|
||||
{
|
||||
return sInitializationCount > 0;
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if (--sInitializationCount == 0)
|
||||
{
|
||||
delete gMasterThreadRecorder;
|
||||
gMasterThreadRecorder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
MasterThreadRecorder& getMasterThreadRecorder()
|
||||
{
|
||||
llassert(gMasterThreadRecorder != NULL);
|
||||
return *gMasterThreadRecorder;
|
||||
}
|
||||
|
||||
LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr()
|
||||
{
|
||||
static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder;
|
||||
return s_thread_recorder;
|
||||
}
|
||||
|
||||
const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder()
|
||||
{
|
||||
return get_thread_recorder_ptr();
|
||||
}
|
||||
|
||||
void set_thread_recorder(ThreadRecorder* recorder)
|
||||
{
|
||||
get_thread_recorder_ptr() = recorder;
|
||||
}
|
||||
|
||||
|
||||
TimeBlockTreeNode::TimeBlockTreeNode()
|
||||
: mBlock(NULL),
|
||||
mParent(NULL),
|
||||
mNeedsSorting(false)
|
||||
{}
|
||||
|
||||
void TimeBlockTreeNode::setParent( TimeBlock* parent )
|
||||
{
|
||||
llassert_always(parent != mBlock);
|
||||
llassert_always(parent != NULL);
|
||||
|
||||
TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(parent->getIndex());
|
||||
if (!parent_tree_node) return;
|
||||
|
||||
if (mParent)
|
||||
{
|
||||
std::vector<TimeBlock*>& children = mParent->getChildren();
|
||||
std::vector<TimeBlock*>::iterator found_it = std::find(children.begin(), children.end(), mBlock);
|
||||
if (found_it != children.end())
|
||||
{
|
||||
children.erase(found_it);
|
||||
}
|
||||
}
|
||||
|
||||
mParent = parent;
|
||||
mBlock->getPrimaryAccumulator()->mParent = parent;
|
||||
parent_tree_node->mChildren.push_back(mBlock);
|
||||
parent_tree_node->mNeedsSorting = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,845 @@
|
|||
/**
|
||||
* @file lltrace.h
|
||||
* @brief Runtime statistics accumulation.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLTRACE_H
|
||||
#define LL_LLTRACE_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llunit.h"
|
||||
#include "llapr.h"
|
||||
#include "llthreadlocalstorage.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
#define LL_RECORD_BLOCK_TIME(block_timer) LLTrace::TimeBlock::Recorder LL_GLUE_TOKENS(block_time_recorder, __COUNTER__)(block_timer);
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
class Recording;
|
||||
|
||||
typedef LLUnit<LLUnits::Bytes, F64> Bytes;
|
||||
typedef LLUnit<LLUnits::Kilobytes, F64> Kilobytes;
|
||||
typedef LLUnit<LLUnits::Megabytes, F64> Megabytes;
|
||||
typedef LLUnit<LLUnits::Gigabytes, F64> Gigabytes;
|
||||
typedef LLUnit<LLUnits::Bits, F64> Bits;
|
||||
typedef LLUnit<LLUnits::Kilobits, F64> Kilobits;
|
||||
typedef LLUnit<LLUnits::Megabits, F64> Megabits;
|
||||
typedef LLUnit<LLUnits::Gigabits, F64> Gigabits;
|
||||
|
||||
typedef LLUnit<LLUnits::Seconds, F64> Seconds;
|
||||
typedef LLUnit<LLUnits::Milliseconds, F64> Milliseconds;
|
||||
typedef LLUnit<LLUnits::Minutes, F64> Minutes;
|
||||
typedef LLUnit<LLUnits::Hours, F64> Hours;
|
||||
typedef LLUnit<LLUnits::Milliseconds, F64> Milliseconds;
|
||||
typedef LLUnit<LLUnits::Microseconds, F64> Microseconds;
|
||||
typedef LLUnit<LLUnits::Nanoseconds, F64> Nanoseconds;
|
||||
|
||||
typedef LLUnit<LLUnits::Meters, F64> Meters;
|
||||
typedef LLUnit<LLUnits::Kilometers, F64> Kilometers;
|
||||
typedef LLUnit<LLUnits::Centimeters, F64> Centimeters;
|
||||
typedef LLUnit<LLUnits::Millimeters, F64> Millimeters;
|
||||
|
||||
void init();
|
||||
void cleanup();
|
||||
bool isInitialized();
|
||||
|
||||
const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder();
|
||||
void set_thread_recorder(class ThreadRecorder*);
|
||||
|
||||
class MasterThreadRecorder& getMasterThreadRecorder();
|
||||
|
||||
// one per thread per type
|
||||
template<typename ACCUMULATOR>
|
||||
class AccumulatorBuffer : public LLRefCount
|
||||
{
|
||||
typedef AccumulatorBuffer<ACCUMULATOR> self_t;
|
||||
static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
|
||||
private:
|
||||
struct StaticAllocationMarker { };
|
||||
|
||||
AccumulatorBuffer(StaticAllocationMarker m)
|
||||
: mStorageSize(0),
|
||||
mStorage(NULL),
|
||||
mNextStorageSlot(0)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer())
|
||||
: mStorageSize(0),
|
||||
mStorage(NULL),
|
||||
mNextStorageSlot(other.mNextStorageSlot)
|
||||
{
|
||||
resize(other.mStorageSize);
|
||||
for (S32 i = 0; i < mNextStorageSlot; i++)
|
||||
{
|
||||
mStorage[i] = other.mStorage[i];
|
||||
}
|
||||
}
|
||||
|
||||
~AccumulatorBuffer()
|
||||
{
|
||||
if (LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage)
|
||||
{
|
||||
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(getDefaultBuffer()->mStorage);
|
||||
}
|
||||
delete[] mStorage;
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index)
|
||||
{
|
||||
return mStorage[index];
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const
|
||||
{
|
||||
return mStorage[index];
|
||||
}
|
||||
|
||||
void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other)
|
||||
{
|
||||
llassert(mNextStorageSlot == other.mNextStorageSlot);
|
||||
|
||||
for (size_t i = 0; i < mNextStorageSlot; i++)
|
||||
{
|
||||
mStorage[i].addSamples(other.mStorage[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
|
||||
{
|
||||
for (size_t i = 0; i < mNextStorageSlot; i++)
|
||||
{
|
||||
mStorage[i] = other.mStorage[i];
|
||||
}
|
||||
}
|
||||
|
||||
void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
|
||||
{
|
||||
for (size_t i = 0; i < mNextStorageSlot; i++)
|
||||
{
|
||||
mStorage[i].reset(other ? &other->mStorage[i] : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void makePrimary()
|
||||
{
|
||||
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage);
|
||||
}
|
||||
|
||||
bool isPrimary() const
|
||||
{
|
||||
return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;
|
||||
}
|
||||
|
||||
LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()
|
||||
{
|
||||
return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();
|
||||
}
|
||||
|
||||
// NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned
|
||||
size_t reserveSlot()
|
||||
{
|
||||
if (LLTrace::isInitialized())
|
||||
{
|
||||
llerrs << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << llendl;
|
||||
}
|
||||
size_t next_slot = mNextStorageSlot++;
|
||||
if (next_slot >= mStorageSize)
|
||||
{
|
||||
resize(mStorageSize + (mStorageSize >> 2));
|
||||
}
|
||||
llassert(mStorage && next_slot < mStorageSize);
|
||||
return next_slot;
|
||||
}
|
||||
|
||||
void resize(size_t new_size)
|
||||
{
|
||||
if (new_size <= mStorageSize) return;
|
||||
|
||||
ACCUMULATOR* old_storage = mStorage;
|
||||
mStorage = new ACCUMULATOR[new_size];
|
||||
if (old_storage)
|
||||
{
|
||||
for (S32 i = 0; i < mStorageSize; i++)
|
||||
{
|
||||
mStorage[i] = old_storage[i];
|
||||
}
|
||||
}
|
||||
mStorageSize = new_size;
|
||||
delete[] old_storage;
|
||||
|
||||
self_t* default_buffer = getDefaultBuffer();
|
||||
if (this != default_buffer
|
||||
&& new_size > default_buffer->size())
|
||||
{
|
||||
//NB: this is not thread safe, but we assume that all resizing occurs during static initialization
|
||||
default_buffer->resize(new_size);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return mNextStorageSlot;
|
||||
}
|
||||
|
||||
static self_t* getDefaultBuffer()
|
||||
{
|
||||
// this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data
|
||||
// so as not to trigger an access violation
|
||||
static self_t* sBuffer = new AccumulatorBuffer(StaticAllocationMarker());
|
||||
static bool sInitialized = false;
|
||||
if (!sInitialized)
|
||||
{
|
||||
sBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE);
|
||||
sInitialized = true;
|
||||
}
|
||||
return sBuffer;
|
||||
}
|
||||
|
||||
private:
|
||||
ACCUMULATOR* mStorage;
|
||||
size_t mStorageSize;
|
||||
size_t mNextStorageSlot;
|
||||
};
|
||||
|
||||
//TODO: replace with decltype when C++11 is enabled
|
||||
template<typename T>
|
||||
struct MeanValueType
|
||||
{
|
||||
typedef F64 type;
|
||||
};
|
||||
|
||||
template<typename ACCUMULATOR>
|
||||
class TraceType
|
||||
: public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>
|
||||
{
|
||||
public:
|
||||
TraceType(const char* name, const char* description = NULL)
|
||||
: LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>(name),
|
||||
mName(name),
|
||||
mDescription(description ? description : ""),
|
||||
mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot())
|
||||
{}
|
||||
|
||||
LL_FORCE_INLINE ACCUMULATOR* getPrimaryAccumulator() const
|
||||
{
|
||||
ACCUMULATOR* accumulator_storage = AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage();
|
||||
return &accumulator_storage[mAccumulatorIndex];
|
||||
}
|
||||
|
||||
size_t getIndex() const { return mAccumulatorIndex; }
|
||||
|
||||
const std::string& getName() const { return mName; }
|
||||
|
||||
protected:
|
||||
const std::string mName;
|
||||
const std::string mDescription;
|
||||
const size_t mAccumulatorIndex;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class MeasurementAccumulator
|
||||
{
|
||||
public:
|
||||
typedef T value_t;
|
||||
typedef MeasurementAccumulator<T> self_t;
|
||||
|
||||
MeasurementAccumulator()
|
||||
: mSum(0),
|
||||
mMin((std::numeric_limits<T>::max)()),
|
||||
mMax((std::numeric_limits<T>::min)()),
|
||||
mMean(0),
|
||||
mVarianceSum(0),
|
||||
mNumSamples(0),
|
||||
mLastValue(0)
|
||||
{}
|
||||
|
||||
void sample(T value)
|
||||
{
|
||||
mNumSamples++;
|
||||
mSum += value;
|
||||
// NOTE: both conditions will hold on first pass through
|
||||
if (value < mMin)
|
||||
{
|
||||
mMin = value;
|
||||
}
|
||||
if (value > mMax)
|
||||
{
|
||||
mMax = value;
|
||||
}
|
||||
F64 old_mean = mMean;
|
||||
mMean += ((F64)value - old_mean) / (F64)mNumSamples;
|
||||
mVarianceSum += ((F64)value - old_mean) * ((F64)value - mMean);
|
||||
mLastValue = value;
|
||||
}
|
||||
|
||||
void addSamples(const self_t& other)
|
||||
{
|
||||
if (other.mNumSamples)
|
||||
{
|
||||
mSum += other.mSum;
|
||||
if (other.mMin < mMin)
|
||||
{
|
||||
mMin = other.mMin;
|
||||
}
|
||||
if (other.mMax > mMax)
|
||||
{
|
||||
mMax = other.mMax;
|
||||
}
|
||||
F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples);
|
||||
mNumSamples += other.mNumSamples;
|
||||
mMean = mMean * weight + other.mMean * (1.f - weight);
|
||||
|
||||
// combine variance (and hence standard deviation) of 2 different sized sample groups using
|
||||
// the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm
|
||||
F64 n_1 = (F64)mNumSamples,
|
||||
n_2 = (F64)other.mNumSamples;
|
||||
F64 m_1 = mMean,
|
||||
m_2 = other.mMean;
|
||||
F64 v_1 = mVarianceSum / mNumSamples,
|
||||
v_2 = other.mVarianceSum / other.mNumSamples;
|
||||
if (n_1 == 0)
|
||||
{
|
||||
mVarianceSum = other.mVarianceSum;
|
||||
}
|
||||
else if (n_2 == 0)
|
||||
{
|
||||
// don't touch variance
|
||||
// mVarianceSum = mVarianceSum;
|
||||
}
|
||||
else
|
||||
{
|
||||
mVarianceSum = (F64)mNumSamples
|
||||
* ((((n_1 - 1.f) * 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));
|
||||
}
|
||||
mLastValue = other.mLastValue;
|
||||
}
|
||||
}
|
||||
|
||||
void reset(const self_t* other)
|
||||
{
|
||||
mNumSamples = 0;
|
||||
mSum = 0;
|
||||
mMin = 0;
|
||||
mMax = 0;
|
||||
mMean = 0;
|
||||
mVarianceSum = 0;
|
||||
mLastValue = other ? other->mLastValue : 0;
|
||||
}
|
||||
|
||||
T getSum() const { return (T)mSum; }
|
||||
T getMin() const { return (T)mMin; }
|
||||
T getMax() const { return (T)mMax; }
|
||||
T getLastValue() const { return (T)mLastValue; }
|
||||
F64 getMean() const { return mMean; }
|
||||
F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); }
|
||||
U32 getSampleCount() const { return mNumSamples; }
|
||||
|
||||
private:
|
||||
T mSum,
|
||||
mMin,
|
||||
mMax,
|
||||
mLastValue;
|
||||
|
||||
F64 mMean,
|
||||
mVarianceSum;
|
||||
|
||||
U32 mNumSamples;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class CountAccumulator
|
||||
{
|
||||
public:
|
||||
typedef CountAccumulator<T> self_t;
|
||||
typedef T value_t;
|
||||
|
||||
CountAccumulator()
|
||||
: mSum(0),
|
||||
mNumSamples(0)
|
||||
{}
|
||||
|
||||
void add(T value)
|
||||
{
|
||||
mNumSamples++;
|
||||
mSum += value;
|
||||
}
|
||||
|
||||
void addSamples(const CountAccumulator<T>& other)
|
||||
{
|
||||
mSum += other.mSum;
|
||||
mNumSamples += other.mNumSamples;
|
||||
}
|
||||
|
||||
void reset(const self_t* other)
|
||||
{
|
||||
mNumSamples = 0;
|
||||
mSum = 0;
|
||||
}
|
||||
|
||||
T getSum() const { return (T)mSum; }
|
||||
|
||||
U32 getSampleCount() const { return mNumSamples; }
|
||||
|
||||
private:
|
||||
T mSum;
|
||||
|
||||
U32 mNumSamples;
|
||||
};
|
||||
|
||||
class TimeBlockAccumulator
|
||||
{
|
||||
public:
|
||||
typedef LLUnit<LLUnits::Seconds, F64> value_t;
|
||||
typedef TimeBlockAccumulator self_t;
|
||||
|
||||
// fake class that allows us to view call count aspect of timeblock accumulator
|
||||
struct CallCountAspect
|
||||
{
|
||||
typedef U32 value_t;
|
||||
};
|
||||
|
||||
struct SelfTimeAspect
|
||||
{
|
||||
typedef LLUnit<LLUnits::Seconds, F64> value_t;
|
||||
};
|
||||
|
||||
TimeBlockAccumulator();
|
||||
void addSamples(const self_t& other);
|
||||
void reset(const self_t* other);
|
||||
|
||||
//
|
||||
// members
|
||||
//
|
||||
U64 mStartTotalTimeCounter,
|
||||
mTotalTimeCounter,
|
||||
mSelfTimeCounter;
|
||||
U32 mCalls;
|
||||
class TimeBlock* mParent; // last acknowledged parent of this time block
|
||||
class TimeBlock* mLastCaller; // used to bootstrap tree construction
|
||||
U16 mActiveCount; // number of timers with this ID active on stack
|
||||
bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct MeanValueType<TraceType<TimeBlockAccumulator> >
|
||||
{
|
||||
typedef LLUnit<LLUnits::Seconds, F64> type;
|
||||
};
|
||||
|
||||
template<>
|
||||
class TraceType<TimeBlockAccumulator::CallCountAspect>
|
||||
: public TraceType<TimeBlockAccumulator>
|
||||
{
|
||||
public:
|
||||
|
||||
TraceType(const char* name, const char* description = "")
|
||||
: TraceType<TimeBlockAccumulator>(name, description)
|
||||
{}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MeanValueType<TraceType<TimeBlockAccumulator::CallCountAspect> >
|
||||
{
|
||||
typedef F64 type;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
class TraceType<TimeBlockAccumulator::SelfTimeAspect>
|
||||
: public TraceType<TimeBlockAccumulator>
|
||||
{
|
||||
public:
|
||||
|
||||
TraceType(const char* name, const char* description = "")
|
||||
: TraceType<TimeBlockAccumulator>(name, description)
|
||||
{}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct MeanValueType<TraceType<TimeBlockAccumulator::SelfTimeAspect> >
|
||||
{
|
||||
typedef LLUnit<LLUnits::Seconds, F64> type;
|
||||
};
|
||||
|
||||
|
||||
class TimeBlock;
|
||||
class TimeBlockTreeNode
|
||||
{
|
||||
public:
|
||||
TimeBlockTreeNode();
|
||||
|
||||
void setParent(TimeBlock* parent);
|
||||
TimeBlock* getParent() { return mParent; }
|
||||
|
||||
TimeBlock* mBlock;
|
||||
TimeBlock* mParent;
|
||||
std::vector<TimeBlock*> mChildren;
|
||||
bool mNeedsSorting;
|
||||
};
|
||||
|
||||
|
||||
template <typename T = F64>
|
||||
class MeasurementStatHandle
|
||||
: public TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >
|
||||
{
|
||||
public:
|
||||
typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t;
|
||||
typedef TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > trace_t;
|
||||
|
||||
MeasurementStatHandle(const char* name, const char* description = NULL)
|
||||
: trace_t(name, description)
|
||||
{}
|
||||
};
|
||||
|
||||
template<typename T, typename VALUE_T>
|
||||
void sample(MeasurementStatHandle<T>& measurement, VALUE_T value)
|
||||
{
|
||||
T converted_value(value);
|
||||
measurement.getPrimaryAccumulator()->sample(LLUnits::rawValue(converted_value));
|
||||
}
|
||||
|
||||
|
||||
template <typename T = F64>
|
||||
class CountStatHandle
|
||||
: public TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >
|
||||
{
|
||||
public:
|
||||
typedef typename LLUnits::HighestPrecisionType<T>::type_t storage_t;
|
||||
typedef TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> > trace_t;
|
||||
|
||||
CountStatHandle(const char* name, const char* description = NULL)
|
||||
: trace_t(name)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
struct MemStatAccumulator
|
||||
{
|
||||
MemStatAccumulator()
|
||||
: mSize(0),
|
||||
mChildSize(0),
|
||||
mAllocatedCount(0),
|
||||
mDeallocatedCount(0)
|
||||
{}
|
||||
|
||||
void addSamples(const MemStatAccumulator& other)
|
||||
{
|
||||
mSize += other.mSize;
|
||||
mChildSize += other.mChildSize;
|
||||
mAllocatedCount += other.mAllocatedCount;
|
||||
mDeallocatedCount += other.mDeallocatedCount;
|
||||
}
|
||||
|
||||
void reset(const MemStatAccumulator* other)
|
||||
{
|
||||
mSize = 0;
|
||||
mChildSize = 0;
|
||||
mAllocatedCount = 0;
|
||||
mDeallocatedCount = 0;
|
||||
}
|
||||
|
||||
size_t mSize,
|
||||
mChildSize;
|
||||
int mAllocatedCount,
|
||||
mDeallocatedCount;
|
||||
};
|
||||
|
||||
class MemStatHandle : public TraceType<MemStatAccumulator>
|
||||
{
|
||||
public:
|
||||
typedef TraceType<MemStatAccumulator> trace_t;
|
||||
MemStatHandle(const char* name)
|
||||
: trace_t(name)
|
||||
{}
|
||||
};
|
||||
|
||||
// measures effective memory footprint of specified type
|
||||
// specialize to cover different types
|
||||
|
||||
template<typename T>
|
||||
struct MemFootprint
|
||||
{
|
||||
static size_t measure(const T& value)
|
||||
{
|
||||
return sizeof(T);
|
||||
}
|
||||
|
||||
static size_t measure()
|
||||
{
|
||||
return sizeof(T);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MemFootprint<T*>
|
||||
{
|
||||
static size_t measure(const T* value)
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return MemFootprint<T>::measure(*value);
|
||||
}
|
||||
|
||||
static size_t measure()
|
||||
{
|
||||
return MemFootprint<T>::measure();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MemFootprint<std::basic_string<T> >
|
||||
{
|
||||
static size_t measure(const std::basic_string<T>& value)
|
||||
{
|
||||
return value.capacity() * sizeof(T);
|
||||
}
|
||||
|
||||
static size_t measure()
|
||||
{
|
||||
return sizeof(std::basic_string<T>);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MemFootprint<std::vector<T> >
|
||||
{
|
||||
static size_t measure(const std::vector<T>& value)
|
||||
{
|
||||
return value.capacity() * MemFootprint<T>::measure();
|
||||
}
|
||||
|
||||
static size_t measure()
|
||||
{
|
||||
return sizeof(std::vector<T>);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MemFootprint<std::list<T> >
|
||||
{
|
||||
static size_t measure(const std::list<T>& value)
|
||||
{
|
||||
return value.size() * (MemFootprint<T>::measure() + sizeof(void*) * 2);
|
||||
}
|
||||
|
||||
static size_t measure()
|
||||
{
|
||||
return sizeof(std::list<T>);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
|
||||
class MemTrackable
|
||||
{
|
||||
template<typename TRACKED, typename TRACKED_IS_TRACKER>
|
||||
struct TrackMemImpl;
|
||||
|
||||
typedef MemTrackable<DERIVED> mem_trackable_t;
|
||||
|
||||
public:
|
||||
typedef void mem_trackable_tag_t;
|
||||
|
||||
virtual ~MemTrackable()
|
||||
{
|
||||
memDisclaim(mMemFootprint);
|
||||
}
|
||||
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mSize += size;
|
||||
accumulator->mAllocatedCount++;
|
||||
}
|
||||
|
||||
return ::operator new(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, size_t size)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mSize -= size;
|
||||
accumulator->mAllocatedCount--;
|
||||
accumulator->mDeallocatedCount++;
|
||||
}
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
void *operator new [](size_t size)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mSize += size;
|
||||
accumulator->mAllocatedCount++;
|
||||
}
|
||||
|
||||
return ::operator new[](size);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, size_t size)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mSize -= size;
|
||||
accumulator->mAllocatedCount--;
|
||||
accumulator->mDeallocatedCount++;
|
||||
}
|
||||
::operator delete[](ptr);
|
||||
}
|
||||
|
||||
// claim memory associated with other objects/data as our own, adding to our calculated footprint
|
||||
template<typename CLAIM_T>
|
||||
CLAIM_T& memClaim(CLAIM_T& value)
|
||||
{
|
||||
TrackMemImpl<CLAIM_T>::claim(*this, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename CLAIM_T>
|
||||
const CLAIM_T& memClaim(const CLAIM_T& value)
|
||||
{
|
||||
TrackMemImpl<CLAIM_T>::claim(*this, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void memClaim(size_t size)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
mMemFootprint += size;
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mSize += size;
|
||||
}
|
||||
}
|
||||
|
||||
// remove memory we had claimed from our calculated footprint
|
||||
template<typename CLAIM_T>
|
||||
CLAIM_T& memDisclaim(CLAIM_T& value)
|
||||
{
|
||||
TrackMemImpl<CLAIM_T>::disclaim(*this, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename CLAIM_T>
|
||||
const CLAIM_T& memDisclaim(const CLAIM_T& value)
|
||||
{
|
||||
TrackMemImpl<CLAIM_T>::disclaim(*this, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void memDisclaim(size_t size)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mSize -= size;
|
||||
}
|
||||
mMemFootprint -= size;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t mMemFootprint;
|
||||
|
||||
template<typename TRACKED, typename TRACKED_IS_TRACKER = void>
|
||||
struct TrackMemImpl
|
||||
{
|
||||
static void claim(mem_trackable_t& tracker, const TRACKED& tracked)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
size_t footprint = MemFootprint<TRACKED>::measure(tracked);
|
||||
accumulator->mSize += footprint;
|
||||
tracker.mMemFootprint += footprint;
|
||||
}
|
||||
}
|
||||
|
||||
static void disclaim(mem_trackable_t& tracker, const TRACKED& tracked)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
size_t footprint = MemFootprint<TRACKED>::measure(tracked);
|
||||
accumulator->mSize -= footprint;
|
||||
tracker.mMemFootprint -= footprint;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TRACKED>
|
||||
struct TrackMemImpl<TRACKED, typename TRACKED::mem_trackable_tag_t>
|
||||
{
|
||||
static void claim(mem_trackable_t& tracker, TRACKED& tracked)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mChildSize += MemFootprint<TRACKED>::measure(tracked);
|
||||
}
|
||||
}
|
||||
|
||||
static void disclaim(mem_trackable_t& tracker, TRACKED& tracked)
|
||||
{
|
||||
MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
|
||||
if (accumulator)
|
||||
{
|
||||
accumulator->mChildSize -= MemFootprint<TRACKED>::measure(tracked);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
#endif // LL_LLTRACE_H
|
||||
|
|
@ -0,0 +1,666 @@
|
|||
/**
|
||||
* @file lltracesampler.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lltrace.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "lltracerecording.h"
|
||||
#include "lltracethreadrecorder.h"
|
||||
#include "llthread.h"
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// RecordingBuffers
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
RecordingBuffers::RecordingBuffers()
|
||||
: mCountsFloat(new AccumulatorBuffer<CountAccumulator<F64> >()),
|
||||
mMeasurementsFloat(new AccumulatorBuffer<MeasurementAccumulator<F64> >()),
|
||||
mCounts(new AccumulatorBuffer<CountAccumulator<S64> >()),
|
||||
mMeasurements(new AccumulatorBuffer<MeasurementAccumulator<S64> >()),
|
||||
mStackTimers(new AccumulatorBuffer<TimeBlockAccumulator>()),
|
||||
mMemStats(new AccumulatorBuffer<MemStatAccumulator>())
|
||||
{}
|
||||
|
||||
void RecordingBuffers::handOffTo(RecordingBuffers& other)
|
||||
{
|
||||
other.mCountsFloat.write()->reset(mCountsFloat);
|
||||
other.mMeasurementsFloat.write()->reset(mMeasurementsFloat);
|
||||
other.mCounts.write()->reset(mCounts);
|
||||
other.mMeasurements.write()->reset(mMeasurements);
|
||||
other.mStackTimers.write()->reset(mStackTimers);
|
||||
other.mMemStats.write()->reset(mMemStats);
|
||||
}
|
||||
|
||||
void RecordingBuffers::makePrimary()
|
||||
{
|
||||
mCountsFloat.write()->makePrimary();
|
||||
mMeasurementsFloat.write()->makePrimary();
|
||||
mCounts.write()->makePrimary();
|
||||
mMeasurements.write()->makePrimary();
|
||||
mStackTimers.write()->makePrimary();
|
||||
mMemStats.write()->makePrimary();
|
||||
|
||||
ThreadRecorder* thread_recorder = get_thread_recorder().get();
|
||||
AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = *mStackTimers.write();
|
||||
// update stacktimer parent pointers
|
||||
for (S32 i = 0, end_i = mStackTimers->size(); i < end_i; i++)
|
||||
{
|
||||
TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i);
|
||||
if (tree_node)
|
||||
{
|
||||
timer_accumulator_buffer[i].mParent = tree_node->mParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RecordingBuffers::isPrimary() const
|
||||
{
|
||||
return mCounts->isPrimary();
|
||||
}
|
||||
|
||||
void RecordingBuffers::makeUnique()
|
||||
{
|
||||
mCountsFloat.makeUnique();
|
||||
mMeasurementsFloat.makeUnique();
|
||||
mCounts.makeUnique();
|
||||
mMeasurements.makeUnique();
|
||||
mStackTimers.makeUnique();
|
||||
mMemStats.makeUnique();
|
||||
}
|
||||
|
||||
void RecordingBuffers::appendBuffers( const RecordingBuffers& other )
|
||||
{
|
||||
mCountsFloat.write()->addSamples(*other.mCountsFloat);
|
||||
mMeasurementsFloat.write()->addSamples(*other.mMeasurementsFloat);
|
||||
mCounts.write()->addSamples(*other.mCounts);
|
||||
mMeasurements.write()->addSamples(*other.mMeasurements);
|
||||
mMemStats.write()->addSamples(*other.mMemStats);
|
||||
mStackTimers.write()->addSamples(*other.mStackTimers);
|
||||
}
|
||||
|
||||
void RecordingBuffers::mergeBuffers( const RecordingBuffers& other)
|
||||
{
|
||||
mCountsFloat.write()->addSamples(*other.mCountsFloat);
|
||||
mMeasurementsFloat.write()->addSamples(*other.mMeasurementsFloat);
|
||||
mCounts.write()->addSamples(*other.mCounts);
|
||||
mMeasurements.write()->addSamples(*other.mMeasurements);
|
||||
mMemStats.write()->addSamples(*other.mMemStats);
|
||||
}
|
||||
|
||||
void RecordingBuffers::resetBuffers(RecordingBuffers* other)
|
||||
{
|
||||
mCountsFloat.write()->reset(other ? other->mCountsFloat : NULL);
|
||||
mMeasurementsFloat.write()->reset(other ? other->mMeasurementsFloat : NULL);
|
||||
mCounts.write()->reset(other ? other->mCounts : NULL);
|
||||
mMeasurements.write()->reset(other ? other->mMeasurements : NULL);
|
||||
mStackTimers.write()->reset(other ? other->mStackTimers : NULL);
|
||||
mMemStats.write()->reset(other ? other->mMemStats : NULL);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Recording
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
Recording::Recording()
|
||||
: mElapsedSeconds(0)
|
||||
{}
|
||||
|
||||
Recording::Recording( const Recording& other )
|
||||
: RecordingBuffers(other),
|
||||
mElapsedSeconds(other.mElapsedSeconds),
|
||||
mSamplingTimer(other.mSamplingTimer)
|
||||
{
|
||||
LLStopWatchControlsMixin<Recording>::setPlayState(other.getPlayState());
|
||||
}
|
||||
|
||||
|
||||
Recording::~Recording()
|
||||
{
|
||||
stop();
|
||||
llassert(isStopped());
|
||||
}
|
||||
|
||||
void Recording::update()
|
||||
{
|
||||
if (isStarted())
|
||||
{
|
||||
LLTrace::get_thread_recorder()->update(this);
|
||||
mSamplingTimer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Recording::handleReset()
|
||||
{
|
||||
resetBuffers();
|
||||
|
||||
mElapsedSeconds = 0.0;
|
||||
mSamplingTimer.reset();
|
||||
}
|
||||
|
||||
void Recording::handleStart()
|
||||
{
|
||||
mSamplingTimer.reset();
|
||||
LLTrace::get_thread_recorder()->activate(this);
|
||||
}
|
||||
|
||||
void Recording::handleStop()
|
||||
{
|
||||
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
|
||||
LLTrace::TimeBlock::processTimes();
|
||||
LLTrace::get_thread_recorder()->deactivate(this);
|
||||
}
|
||||
|
||||
void Recording::handleSplitTo(Recording& other)
|
||||
{
|
||||
stop();
|
||||
other.restart();
|
||||
handOffTo(other);
|
||||
}
|
||||
|
||||
void Recording::appendRecording( const Recording& other )
|
||||
{
|
||||
appendBuffers(other);
|
||||
mElapsedSeconds += other.mElapsedSeconds;
|
||||
}
|
||||
|
||||
void Recording::mergeRecording( const Recording& other)
|
||||
{
|
||||
mergeBuffers(other);
|
||||
}
|
||||
|
||||
LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) const
|
||||
{
|
||||
const TimeBlockAccumulator& accumulator = (*mStackTimers)[stat.getIndex()];
|
||||
return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
|
||||
/ (F64)LLTrace::TimeBlock::countsPerSecond();
|
||||
}
|
||||
|
||||
LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const
|
||||
{
|
||||
const TimeBlockAccumulator& accumulator = (*mStackTimers)[stat.getIndex()];
|
||||
return (F64)(accumulator.mSelfTimeCounter) / (F64)LLTrace::TimeBlock::countsPerSecond();
|
||||
}
|
||||
|
||||
|
||||
U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
|
||||
{
|
||||
return (*mStackTimers)[stat.getIndex()].mCalls;
|
||||
}
|
||||
|
||||
LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat) const
|
||||
{
|
||||
const TimeBlockAccumulator& accumulator = (*mStackTimers)[stat.getIndex()];
|
||||
|
||||
return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
|
||||
/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
|
||||
}
|
||||
|
||||
LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const
|
||||
{
|
||||
const TimeBlockAccumulator& accumulator = (*mStackTimers)[stat.getIndex()];
|
||||
|
||||
return (F64)(accumulator.mSelfTimeCounter)
|
||||
/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
|
||||
}
|
||||
|
||||
F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const
|
||||
{
|
||||
return (F32)(*mStackTimers)[stat.getIndex()].mCalls / mElapsedSeconds;
|
||||
}
|
||||
|
||||
LLUnit<LLUnits::Bytes, U32> Recording::getSum(const TraceType<MemStatAccumulator>& stat) const
|
||||
{
|
||||
return (*mMemStats)[stat.getIndex()].mAllocatedCount;
|
||||
}
|
||||
|
||||
LLUnit<LLUnits::Bytes, F32> Recording::getPerSec(const TraceType<MemStatAccumulator>& stat) const
|
||||
{
|
||||
return (F32)(*mMemStats)[stat.getIndex()].mAllocatedCount / mElapsedSeconds;
|
||||
}
|
||||
|
||||
|
||||
F64 Recording::getSum( const TraceType<CountAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mCountsFloat)[stat.getIndex()].getSum();
|
||||
}
|
||||
|
||||
S64 Recording::getSum( const TraceType<CountAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mCounts)[stat.getIndex()].getSum();
|
||||
}
|
||||
|
||||
F64 Recording::getSum( const TraceType<MeasurementAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (F64)(*mMeasurementsFloat)[stat.getIndex()].getSum();
|
||||
}
|
||||
|
||||
S64 Recording::getSum( const TraceType<MeasurementAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (S64)(*mMeasurements)[stat.getIndex()].getSum();
|
||||
}
|
||||
|
||||
|
||||
|
||||
F64 Recording::getPerSec( const TraceType<CountAccumulator<F64> >& stat ) const
|
||||
{
|
||||
F64 sum = (*mCountsFloat)[stat.getIndex()].getSum();
|
||||
return (sum != 0.0)
|
||||
? (sum / mElapsedSeconds)
|
||||
: 0.0;
|
||||
}
|
||||
|
||||
F64 Recording::getPerSec( const TraceType<CountAccumulator<S64> >& stat ) const
|
||||
{
|
||||
S64 sum = (*mCounts)[stat.getIndex()].getSum();
|
||||
return (sum != 0)
|
||||
? ((F64)sum / mElapsedSeconds)
|
||||
: 0.0;
|
||||
}
|
||||
|
||||
U32 Recording::getSampleCount( const TraceType<CountAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mCountsFloat)[stat.getIndex()].getSampleCount();
|
||||
}
|
||||
|
||||
U32 Recording::getSampleCount( const TraceType<CountAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurementsFloat)[stat.getIndex()].getSampleCount();
|
||||
}
|
||||
|
||||
F64 Recording::getMin( const TraceType<MeasurementAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurementsFloat)[stat.getIndex()].getMin();
|
||||
}
|
||||
|
||||
S64 Recording::getMin( const TraceType<MeasurementAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurements)[stat.getIndex()].getMin();
|
||||
}
|
||||
|
||||
F64 Recording::getMax( const TraceType<MeasurementAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurementsFloat)[stat.getIndex()].getMax();
|
||||
}
|
||||
|
||||
S64 Recording::getMax( const TraceType<MeasurementAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurements)[stat.getIndex()].getMax();
|
||||
}
|
||||
|
||||
F64 Recording::getMean( const TraceType<MeasurementAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurementsFloat)[stat.getIndex()].getMean();
|
||||
}
|
||||
|
||||
F64 Recording::getMean( const TraceType<MeasurementAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurements)[stat.getIndex()].getMean();
|
||||
}
|
||||
|
||||
F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurementsFloat)[stat.getIndex()].getStandardDeviation();
|
||||
}
|
||||
|
||||
F64 Recording::getStandardDeviation( const TraceType<MeasurementAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurements)[stat.getIndex()].getStandardDeviation();
|
||||
}
|
||||
|
||||
F64 Recording::getLastValue( const TraceType<MeasurementAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurementsFloat)[stat.getIndex()].getLastValue();
|
||||
}
|
||||
|
||||
S64 Recording::getLastValue( const TraceType<MeasurementAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurements)[stat.getIndex()].getLastValue();
|
||||
}
|
||||
|
||||
U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<F64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurementsFloat)[stat.getIndex()].getSampleCount();
|
||||
}
|
||||
|
||||
U32 Recording::getSampleCount( const TraceType<MeasurementAccumulator<S64> >& stat ) const
|
||||
{
|
||||
return (*mMeasurements)[stat.getIndex()].getSampleCount();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// PeriodicRecording
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
PeriodicRecording::PeriodicRecording( U32 num_periods, EPlayState state)
|
||||
: mAutoResize(num_periods == 0),
|
||||
mCurPeriod(0),
|
||||
mTotalValid(false)
|
||||
{
|
||||
if (num_periods)
|
||||
{
|
||||
mRecordingPeriods.resize(num_periods);
|
||||
}
|
||||
setPlayState(state);
|
||||
}
|
||||
|
||||
void PeriodicRecording::nextPeriod()
|
||||
{
|
||||
EPlayState play_state = getPlayState();
|
||||
Recording& old_recording = getCurRecordingPeriod();
|
||||
if (mAutoResize)
|
||||
{
|
||||
mRecordingPeriods.push_back(Recording());
|
||||
}
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
mCurPeriod = (num_periods > 0)
|
||||
? (mCurPeriod + 1) % num_periods
|
||||
: mCurPeriod + 1;
|
||||
old_recording.splitTo(getCurRecordingPeriod());
|
||||
|
||||
switch(play_state)
|
||||
{
|
||||
case STOPPED:
|
||||
getCurRecordingPeriod().stop();
|
||||
break;
|
||||
case PAUSED:
|
||||
getCurRecordingPeriod().pause();
|
||||
break;
|
||||
case STARTED:
|
||||
break;
|
||||
}
|
||||
// new period, need to recalculate total
|
||||
mTotalValid = false;
|
||||
}
|
||||
|
||||
Recording& PeriodicRecording::getTotalRecording()
|
||||
{
|
||||
if (!mTotalValid)
|
||||
{
|
||||
mTotalRecording.reset();
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
|
||||
if (num_periods)
|
||||
{
|
||||
for (S32 i = mCurPeriod + 1; i < mCurPeriod + num_periods; i++)
|
||||
{
|
||||
mTotalRecording.appendRecording(mRecordingPeriods[i % num_periods]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (S32 i = 0; i < mCurPeriod; i++)
|
||||
{
|
||||
mTotalRecording.appendRecording(mRecordingPeriods[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
mTotalValid = true;
|
||||
return mTotalRecording;
|
||||
}
|
||||
|
||||
void PeriodicRecording::start()
|
||||
{
|
||||
getCurRecordingPeriod().start();
|
||||
}
|
||||
|
||||
void PeriodicRecording::stop()
|
||||
{
|
||||
getCurRecordingPeriod().stop();
|
||||
}
|
||||
|
||||
void PeriodicRecording::pause()
|
||||
{
|
||||
getCurRecordingPeriod().pause();
|
||||
}
|
||||
|
||||
void PeriodicRecording::resume()
|
||||
{
|
||||
getCurRecordingPeriod().resume();
|
||||
}
|
||||
|
||||
void PeriodicRecording::restart()
|
||||
{
|
||||
getCurRecordingPeriod().restart();
|
||||
}
|
||||
|
||||
void PeriodicRecording::reset()
|
||||
{
|
||||
getCurRecordingPeriod().reset();
|
||||
}
|
||||
|
||||
void PeriodicRecording::splitTo(PeriodicRecording& other)
|
||||
{
|
||||
getCurRecordingPeriod().splitTo(other.getCurRecordingPeriod());
|
||||
}
|
||||
|
||||
void PeriodicRecording::splitFrom(PeriodicRecording& other)
|
||||
{
|
||||
getCurRecordingPeriod().splitFrom(other.getCurRecordingPeriod());
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// ExtendableRecording
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ExtendableRecording::extend()
|
||||
{
|
||||
// stop recording to get latest data
|
||||
mPotentialRecording.stop();
|
||||
// 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::start()
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::start();
|
||||
mPotentialRecording.start();
|
||||
}
|
||||
|
||||
void ExtendableRecording::stop()
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::stop();
|
||||
mPotentialRecording.stop();
|
||||
}
|
||||
|
||||
void ExtendableRecording::pause()
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::pause();
|
||||
mPotentialRecording.pause();
|
||||
}
|
||||
|
||||
void ExtendableRecording::resume()
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::resume();
|
||||
mPotentialRecording.resume();
|
||||
}
|
||||
|
||||
void ExtendableRecording::restart()
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::restart();
|
||||
mAcceptedRecording.reset();
|
||||
mPotentialRecording.restart();
|
||||
}
|
||||
|
||||
void ExtendableRecording::reset()
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::reset();
|
||||
mAcceptedRecording.reset();
|
||||
mPotentialRecording.reset();
|
||||
}
|
||||
|
||||
void ExtendableRecording::splitTo(ExtendableRecording& other)
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::splitTo(other);
|
||||
mPotentialRecording.splitTo(other.mPotentialRecording);
|
||||
}
|
||||
|
||||
void ExtendableRecording::splitFrom(ExtendableRecording& other)
|
||||
{
|
||||
LLStopWatchControlsMixin<ExtendableRecording>::splitFrom(other);
|
||||
mPotentialRecording.splitFrom(other.mPotentialRecording);
|
||||
}
|
||||
|
||||
PeriodicRecording& get_frame_recording()
|
||||
{
|
||||
static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(1000, PeriodicRecording::STARTED));
|
||||
return *sRecording;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::start()
|
||||
{
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
handleReset();
|
||||
handleStart();
|
||||
break;
|
||||
case PAUSED:
|
||||
handleStart();
|
||||
break;
|
||||
case STARTED:
|
||||
handleReset();
|
||||
break;
|
||||
default:
|
||||
llassert(false);
|
||||
break;
|
||||
}
|
||||
mPlayState = STARTED;
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::stop()
|
||||
{
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
break;
|
||||
case PAUSED:
|
||||
handleStop();
|
||||
break;
|
||||
case STARTED:
|
||||
handleStop();
|
||||
break;
|
||||
default:
|
||||
llassert(false);
|
||||
break;
|
||||
}
|
||||
mPlayState = STOPPED;
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::pause()
|
||||
{
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
break;
|
||||
case PAUSED:
|
||||
break;
|
||||
case STARTED:
|
||||
handleStop();
|
||||
break;
|
||||
default:
|
||||
llassert(false);
|
||||
break;
|
||||
}
|
||||
mPlayState = PAUSED;
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::resume()
|
||||
{
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
handleStart();
|
||||
break;
|
||||
case PAUSED:
|
||||
handleStart();
|
||||
break;
|
||||
case STARTED:
|
||||
break;
|
||||
default:
|
||||
llassert(false);
|
||||
break;
|
||||
}
|
||||
mPlayState = STARTED;
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::restart()
|
||||
{
|
||||
switch (mPlayState)
|
||||
{
|
||||
case STOPPED:
|
||||
handleReset();
|
||||
handleStart();
|
||||
break;
|
||||
case PAUSED:
|
||||
handleReset();
|
||||
handleStart();
|
||||
break;
|
||||
case STARTED:
|
||||
handleReset();
|
||||
break;
|
||||
default:
|
||||
llassert(false);
|
||||
break;
|
||||
}
|
||||
mPlayState = STARTED;
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::reset()
|
||||
{
|
||||
handleReset();
|
||||
}
|
||||
|
||||
void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state )
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case STOPPED:
|
||||
stop();
|
||||
break;
|
||||
case PAUSED:
|
||||
pause();
|
||||
break;
|
||||
case STARTED:
|
||||
start();
|
||||
break;
|
||||
default:
|
||||
llassert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
mPlayState = state;
|
||||
}
|
||||
|
|
@ -0,0 +1,424 @@
|
|||
/**
|
||||
* @file lltracerecording.h
|
||||
* @brief Sampling object for collecting runtime statistics originating from lltrace.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLTRACERECORDING_H
|
||||
#define LL_LLTRACERECORDING_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include "llpointer.h"
|
||||
#include "lltimer.h"
|
||||
#include "lltrace.h"
|
||||
|
||||
class LLStopWatchControlsMixinCommon
|
||||
{
|
||||
public:
|
||||
virtual ~LLStopWatchControlsMixinCommon() {}
|
||||
|
||||
enum EPlayState
|
||||
{
|
||||
STOPPED,
|
||||
PAUSED,
|
||||
STARTED
|
||||
};
|
||||
|
||||
virtual void start();
|
||||
virtual void stop();
|
||||
virtual void pause();
|
||||
virtual void resume();
|
||||
virtual void restart();
|
||||
virtual void reset();
|
||||
|
||||
bool isStarted() const { return mPlayState == STARTED; }
|
||||
bool isPaused() const { return mPlayState == PAUSED; }
|
||||
bool isStopped() const { return mPlayState == STOPPED; }
|
||||
EPlayState getPlayState() const { return mPlayState; }
|
||||
// force play state to specific value by calling appropriate handle* methods
|
||||
void setPlayState(EPlayState state);
|
||||
|
||||
protected:
|
||||
LLStopWatchControlsMixinCommon()
|
||||
: mPlayState(STOPPED)
|
||||
{}
|
||||
|
||||
private:
|
||||
// trigger active behavior (without reset)
|
||||
virtual void handleStart(){};
|
||||
// stop active behavior
|
||||
virtual void handleStop(){};
|
||||
// clear accumulated state, can be called while started
|
||||
virtual void handleReset(){};
|
||||
|
||||
EPlayState mPlayState;
|
||||
};
|
||||
|
||||
template<typename DERIVED>
|
||||
class LLStopWatchControlsMixin
|
||||
: public LLStopWatchControlsMixinCommon
|
||||
{
|
||||
public:
|
||||
typedef LLStopWatchControlsMixin<DERIVED> self_t;
|
||||
virtual void splitTo(DERIVED& other)
|
||||
{
|
||||
handleSplitTo(other);
|
||||
}
|
||||
|
||||
virtual void splitFrom(DERIVED& other)
|
||||
{
|
||||
static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this));
|
||||
}
|
||||
private:
|
||||
// atomically stop this object while starting the other
|
||||
// no data can be missed in between stop and start
|
||||
virtual void handleSplitTo(DERIVED& other) {};
|
||||
|
||||
};
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
class RecordingBuffers
|
||||
{
|
||||
public:
|
||||
RecordingBuffers();
|
||||
|
||||
void handOffTo(RecordingBuffers& other);
|
||||
void makePrimary();
|
||||
bool isPrimary() const;
|
||||
|
||||
void makeUnique();
|
||||
|
||||
void appendBuffers(const RecordingBuffers& other);
|
||||
void mergeBuffers(const RecordingBuffers& other);
|
||||
void resetBuffers(RecordingBuffers* other = NULL);
|
||||
|
||||
protected:
|
||||
LLCopyOnWritePointer<AccumulatorBuffer<CountAccumulator<F64> > > mCountsFloat;
|
||||
LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<F64> > > mMeasurementsFloat;
|
||||
LLCopyOnWritePointer<AccumulatorBuffer<CountAccumulator<S64> > > mCounts;
|
||||
LLCopyOnWritePointer<AccumulatorBuffer<MeasurementAccumulator<S64> > > mMeasurements;
|
||||
LLCopyOnWritePointer<AccumulatorBuffer<TimeBlockAccumulator> > mStackTimers;
|
||||
LLCopyOnWritePointer<AccumulatorBuffer<MemStatAccumulator> > mMemStats;
|
||||
};
|
||||
|
||||
class Recording : public LLStopWatchControlsMixin<Recording>, public RecordingBuffers
|
||||
{
|
||||
public:
|
||||
Recording();
|
||||
|
||||
Recording(const Recording& other);
|
||||
~Recording();
|
||||
|
||||
// accumulate data from subsequent, non-overlapping recording
|
||||
void appendRecording(const Recording& other);
|
||||
|
||||
// gather data from recording, ignoring time relationship (for example, pulling data from slave threads)
|
||||
void mergeRecording(const Recording& other);
|
||||
|
||||
// grab latest recorded data
|
||||
void update();
|
||||
|
||||
// Timer accessors
|
||||
LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator>& stat) const;
|
||||
LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const;
|
||||
U32 getSum(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const;
|
||||
|
||||
LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator>& stat) const;
|
||||
LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeAspect>& stat) const;
|
||||
F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountAspect>& stat) const;
|
||||
|
||||
// Memory accessors
|
||||
LLUnit<LLUnits::Bytes, U32> getSum(const TraceType<MemStatAccumulator>& stat) const;
|
||||
LLUnit<LLUnits::Bytes, F32> getPerSec(const TraceType<MemStatAccumulator>& stat) const;
|
||||
|
||||
// CountStatHandle accessors
|
||||
F64 getSum(const TraceType<CountAccumulator<F64> >& stat) const;
|
||||
S64 getSum(const TraceType<CountAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getSum(const CountStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getSum(static_cast<const TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
F64 getPerSec(const TraceType<CountAccumulator<F64> >& stat) const;
|
||||
F64 getPerSec(const TraceType<CountAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getPerSec(const CountStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getPerSec(static_cast<const TraceType<CountAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
U32 getSampleCount(const TraceType<CountAccumulator<F64> >& stat) const;
|
||||
U32 getSampleCount(const TraceType<CountAccumulator<S64> >& stat) const;
|
||||
|
||||
|
||||
// MeasurementStatHandle accessors
|
||||
F64 getSum(const TraceType<MeasurementAccumulator<F64> >& stat) const;
|
||||
S64 getSum(const TraceType<MeasurementAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getSum(const MeasurementStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getSum(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
F64 getMin(const TraceType<MeasurementAccumulator<F64> >& stat) const;
|
||||
S64 getMin(const TraceType<MeasurementAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getMin(const MeasurementStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getMin(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
F64 getMax(const TraceType<MeasurementAccumulator<F64> >& stat) const;
|
||||
S64 getMax(const TraceType<MeasurementAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getMax(const MeasurementStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getMax(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
F64 getMean(const TraceType<MeasurementAccumulator<F64> >& stat) const;
|
||||
F64 getMean(const TraceType<MeasurementAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getMean(MeasurementStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
F64 getStandardDeviation(const TraceType<MeasurementAccumulator<F64> >& stat) const;
|
||||
F64 getStandardDeviation(const TraceType<MeasurementAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getStandardDeviation(const MeasurementStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getMean(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
F64 getLastValue(const TraceType<MeasurementAccumulator<F64> >& stat) const;
|
||||
S64 getLastValue(const TraceType<MeasurementAccumulator<S64> >& stat) const;
|
||||
template <typename T>
|
||||
T getLastValue(const MeasurementStatHandle<T>& stat) const
|
||||
{
|
||||
return (T)getLastValue(static_cast<const TraceType<MeasurementAccumulator<typename LLUnits::HighestPrecisionType<T>::type_t> >&> (stat));
|
||||
}
|
||||
|
||||
U32 getSampleCount(const TraceType<MeasurementAccumulator<F64> >& stat) const;
|
||||
U32 getSampleCount(const TraceType<MeasurementAccumulator<S64> >& stat) const;
|
||||
|
||||
LLUnit<LLUnits::Seconds, F64> getDuration() const { return LLUnit<LLUnits::Seconds, F64>(mElapsedSeconds); }
|
||||
|
||||
private:
|
||||
friend class ThreadRecorder;
|
||||
|
||||
// implementation for LLStopWatchControlsMixin
|
||||
/*virtual*/ void handleStart();
|
||||
/*virtual*/ void handleStop();
|
||||
/*virtual*/ void handleReset();
|
||||
/*virtual*/ void handleSplitTo(Recording& other);
|
||||
|
||||
// returns data for current thread
|
||||
class ThreadRecorder* getThreadRecorder();
|
||||
|
||||
LLTimer mSamplingTimer;
|
||||
F64 mElapsedSeconds;
|
||||
};
|
||||
|
||||
class LL_COMMON_API PeriodicRecording
|
||||
: public LLStopWatchControlsMixin<PeriodicRecording>
|
||||
{
|
||||
public:
|
||||
PeriodicRecording(U32 num_periods, EPlayState state = STOPPED);
|
||||
|
||||
void nextPeriod();
|
||||
U32 getNumPeriods() { return mRecordingPeriods.size(); }
|
||||
|
||||
Recording& getLastRecordingPeriod()
|
||||
{
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
return mRecordingPeriods[(mCurPeriod + num_periods - 1) % num_periods];
|
||||
}
|
||||
|
||||
const Recording& getLastRecordingPeriod() const
|
||||
{
|
||||
return getPrevRecordingPeriod(1);
|
||||
}
|
||||
|
||||
Recording& getCurRecordingPeriod()
|
||||
{
|
||||
return mRecordingPeriods[mCurPeriod];
|
||||
}
|
||||
|
||||
const Recording& getCurRecordingPeriod() const
|
||||
{
|
||||
return mRecordingPeriods[mCurPeriod];
|
||||
}
|
||||
|
||||
Recording& getPrevRecordingPeriod(U32 offset)
|
||||
{
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
offset = llclamp(offset, 0u, num_periods - 1);
|
||||
return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
|
||||
}
|
||||
|
||||
const Recording& getPrevRecordingPeriod(U32 offset) const
|
||||
{
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
offset = llclamp(offset, 0u, num_periods - 1);
|
||||
return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
|
||||
}
|
||||
|
||||
Recording snapshotCurRecordingPeriod() const
|
||||
{
|
||||
Recording recording_copy(getCurRecordingPeriod());
|
||||
recording_copy.stop();
|
||||
return recording_copy;
|
||||
}
|
||||
|
||||
Recording& getTotalRecording();
|
||||
|
||||
template <typename T>
|
||||
typename T::value_t getPeriodMin(const TraceType<T>& stat) const
|
||||
{
|
||||
typename T::value_t min_val = (std::numeric_limits<typename T::value_t>::max)();
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
for (S32 i = 0; i < num_periods; i++)
|
||||
{
|
||||
min_val = llmin(min_val, mRecordingPeriods[i].getSum(stat));
|
||||
}
|
||||
return min_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
F64 getPeriodMinPerSec(const TraceType<T>& stat) const
|
||||
{
|
||||
F64 min_val = (std::numeric_limits<F64>::max)();
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
for (S32 i = 0; i < num_periods; i++)
|
||||
{
|
||||
min_val = llmin(min_val, mRecordingPeriods[i].getPerSec(stat));
|
||||
}
|
||||
return min_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename T::value_t getPeriodMax(const TraceType<T>& stat) const
|
||||
{
|
||||
typename T::value_t max_val = (std::numeric_limits<typename T::value_t>::min)();
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
for (S32 i = 0; i < num_periods; i++)
|
||||
{
|
||||
max_val = llmax(max_val, mRecordingPeriods[i].getSum(stat));
|
||||
}
|
||||
return max_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
F64 getPeriodMaxPerSec(const TraceType<T>& stat) const
|
||||
{
|
||||
F64 max_val = (std::numeric_limits<F64>::min)();
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
for (S32 i = 0; i < num_periods; i++)
|
||||
{
|
||||
max_val = llmax(max_val, mRecordingPeriods[i].getPerSec(stat));
|
||||
}
|
||||
return max_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename MeanValueType<TraceType<T> >::type getPeriodMean(const TraceType<T>& stat) const
|
||||
{
|
||||
typename MeanValueType<TraceType<T> >::type mean = 0.0;
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
for (S32 i = 0; i < num_periods; i++)
|
||||
{
|
||||
if (mRecordingPeriods[i].getDuration() > 0.f)
|
||||
{
|
||||
mean += mRecordingPeriods[i].getSum(stat);
|
||||
}
|
||||
}
|
||||
mean /= num_periods;
|
||||
return mean;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename MeanValueType<TraceType<T> >::type getPeriodMeanPerSec(const TraceType<T>& stat) const
|
||||
{
|
||||
typename MeanValueType<TraceType<T> >::type mean = 0.0;
|
||||
U32 num_periods = mRecordingPeriods.size();
|
||||
for (S32 i = 0; i < num_periods; i++)
|
||||
{
|
||||
if (mRecordingPeriods[i].getDuration() > 0.f)
|
||||
{
|
||||
mean += mRecordingPeriods[i].getPerSec(stat);
|
||||
}
|
||||
}
|
||||
mean /= num_periods;
|
||||
return mean;
|
||||
}
|
||||
|
||||
// implementation for LLStopWatchControlsMixin
|
||||
/*virtual*/ void start();
|
||||
/*virtual*/ void stop();
|
||||
/*virtual*/ void pause();
|
||||
/*virtual*/ void resume();
|
||||
/*virtual*/ void restart();
|
||||
/*virtual*/ void reset();
|
||||
/*virtual*/ void splitTo(PeriodicRecording& other);
|
||||
/*virtual*/ void splitFrom(PeriodicRecording& other);
|
||||
|
||||
private:
|
||||
std::vector<Recording> mRecordingPeriods;
|
||||
Recording mTotalRecording;
|
||||
bool mTotalValid;
|
||||
const bool mAutoResize;
|
||||
S32 mCurPeriod;
|
||||
};
|
||||
|
||||
PeriodicRecording& get_frame_recording();
|
||||
|
||||
class ExtendableRecording
|
||||
: public LLStopWatchControlsMixin<ExtendableRecording>
|
||||
{
|
||||
public:
|
||||
void extend();
|
||||
|
||||
Recording& getAcceptedRecording() { return mAcceptedRecording; }
|
||||
|
||||
// implementation for LLStopWatchControlsMixin
|
||||
/*virtual*/ void start();
|
||||
/*virtual*/ void stop();
|
||||
/*virtual*/ void pause();
|
||||
/*virtual*/ void resume();
|
||||
/*virtual*/ void restart();
|
||||
/*virtual*/ void reset();
|
||||
/*virtual*/ void splitTo(ExtendableRecording& other);
|
||||
/*virtual*/ void splitFrom(ExtendableRecording& other);
|
||||
private:
|
||||
Recording mAcceptedRecording;
|
||||
Recording mPotentialRecording;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LL_LLTRACERECORDING_H
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
/**
|
||||
* @file lltracethreadrecorder.cpp
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lltracethreadrecorder.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// ThreadRecorder
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
ThreadRecorder::ThreadRecorder()
|
||||
{
|
||||
//NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies
|
||||
set_thread_recorder(this);
|
||||
TimeBlock& root_time_block = TimeBlock::getRootTimeBlock();
|
||||
|
||||
ThreadTimerStack* timer_stack = ThreadTimerStack::getInstance();
|
||||
timer_stack->mTimeBlock = &root_time_block;
|
||||
timer_stack->mActiveTimer = NULL;
|
||||
|
||||
mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size();
|
||||
mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes];
|
||||
|
||||
mThreadRecording.start();
|
||||
|
||||
// initialize time block parent pointers
|
||||
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
TimeBlock& time_block = *it;
|
||||
TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()];
|
||||
tree_node.mBlock = &time_block;
|
||||
tree_node.mParent = &root_time_block;
|
||||
|
||||
it->getPrimaryAccumulator()->mParent = &root_time_block;
|
||||
}
|
||||
|
||||
mRootTimer = new BlockTimer(root_time_block);
|
||||
timer_stack->mActiveTimer = mRootTimer;
|
||||
|
||||
TimeBlock::getRootTimeBlock().getPrimaryAccumulator()->mActiveCount = 1;
|
||||
}
|
||||
|
||||
ThreadRecorder::~ThreadRecorder()
|
||||
{
|
||||
delete mRootTimer;
|
||||
|
||||
while(mActiveRecordings.size())
|
||||
{
|
||||
mActiveRecordings.front()->mTargetRecording->stop();
|
||||
}
|
||||
set_thread_recorder(NULL);
|
||||
delete[] mTimeBlockTreeNodes;
|
||||
}
|
||||
|
||||
TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)
|
||||
{
|
||||
if (0 <= index && index < mNumTimeBlockTreeNodes)
|
||||
{
|
||||
return &mTimeBlockTreeNodes[index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void ThreadRecorder::activate( Recording* recording )
|
||||
{
|
||||
ActiveRecording* active_recording = new ActiveRecording(recording);
|
||||
if (!mActiveRecordings.empty())
|
||||
{
|
||||
mActiveRecordings.front()->mPartialRecording.handOffTo(active_recording->mPartialRecording);
|
||||
}
|
||||
mActiveRecordings.push_front(active_recording);
|
||||
|
||||
mActiveRecordings.front()->mPartialRecording.makePrimary();
|
||||
}
|
||||
|
||||
ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::update( Recording* recording )
|
||||
{
|
||||
active_recording_list_t::iterator it, end_it;
|
||||
for (it = mActiveRecordings.begin(), end_it = mActiveRecordings.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
active_recording_list_t::iterator next_it = it;
|
||||
++next_it;
|
||||
|
||||
// if we have another recording further down in the stack...
|
||||
if (next_it != mActiveRecordings.end())
|
||||
{
|
||||
// ...push our gathered data down to it
|
||||
(*next_it)->mPartialRecording.appendBuffers((*it)->mPartialRecording);
|
||||
}
|
||||
|
||||
// copy accumulated measurements into result buffer and clear accumulator (mPartialRecording)
|
||||
(*it)->moveBaselineToTarget();
|
||||
|
||||
if ((*it)->mTargetRecording == recording)
|
||||
{
|
||||
// found the recording, so return it
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (it == end_it)
|
||||
{
|
||||
llwarns << "Recording not active on this thread" << llendl;
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
AccumulatorBuffer<CountAccumulator<F64> > gCountsFloat;
|
||||
AccumulatorBuffer<MeasurementAccumulator<F64> > gMeasurementsFloat;
|
||||
AccumulatorBuffer<CountAccumulator<S64> > gCounts;
|
||||
AccumulatorBuffer<MeasurementAccumulator<S64> > gMeasurements;
|
||||
AccumulatorBuffer<TimeBlockAccumulator> gStackTimers;
|
||||
AccumulatorBuffer<MemStatAccumulator> gMemStats;
|
||||
|
||||
void ThreadRecorder::deactivate( Recording* recording )
|
||||
{
|
||||
active_recording_list_t::iterator it = update(recording);
|
||||
if (it != mActiveRecordings.end())
|
||||
{
|
||||
// and if we've found the recording we wanted to update
|
||||
active_recording_list_t::iterator next_it = it;
|
||||
++next_it;
|
||||
if (next_it != mActiveRecordings.end())
|
||||
{
|
||||
(*next_it)->mTargetRecording->makePrimary();
|
||||
}
|
||||
|
||||
delete *it;
|
||||
mActiveRecordings.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target )
|
||||
: mTargetRecording(target)
|
||||
{
|
||||
}
|
||||
|
||||
void ThreadRecorder::ActiveRecording::moveBaselineToTarget()
|
||||
{
|
||||
mTargetRecording->appendBuffers(mPartialRecording);
|
||||
mPartialRecording.resetBuffers();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// SlaveThreadRecorder
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
SlaveThreadRecorder::SlaveThreadRecorder()
|
||||
{
|
||||
getMasterThreadRecorder().addSlaveThread(this);
|
||||
}
|
||||
|
||||
SlaveThreadRecorder::~SlaveThreadRecorder()
|
||||
{
|
||||
getMasterThreadRecorder().removeSlaveThread(this);
|
||||
}
|
||||
|
||||
void SlaveThreadRecorder::pushToMaster()
|
||||
{
|
||||
mThreadRecording.stop();
|
||||
{
|
||||
LLMutexLock(getMasterThreadRecorder().getSlaveListMutex());
|
||||
mSharedData.appendFrom(mThreadRecording);
|
||||
}
|
||||
mThreadRecording.start();
|
||||
}
|
||||
|
||||
void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source )
|
||||
{
|
||||
LLMutexLock lock(&mRecordingMutex);
|
||||
mRecording.appendRecording(source);
|
||||
}
|
||||
|
||||
void SlaveThreadRecorder::SharedData::appendTo( Recording& sink )
|
||||
{
|
||||
LLMutexLock lock(&mRecordingMutex);
|
||||
sink.appendRecording(mRecording);
|
||||
}
|
||||
|
||||
void SlaveThreadRecorder::SharedData::mergeFrom( const RecordingBuffers& source )
|
||||
{
|
||||
LLMutexLock lock(&mRecordingMutex);
|
||||
mRecording.mergeBuffers(source);
|
||||
}
|
||||
|
||||
void SlaveThreadRecorder::SharedData::mergeTo( RecordingBuffers& sink )
|
||||
{
|
||||
LLMutexLock lock(&mRecordingMutex);
|
||||
sink.mergeBuffers(mRecording);
|
||||
}
|
||||
|
||||
void SlaveThreadRecorder::SharedData::reset()
|
||||
{
|
||||
LLMutexLock lock(&mRecordingMutex);
|
||||
mRecording.reset();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// MasterThreadRecorder
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data");
|
||||
void MasterThreadRecorder::pullFromSlaveThreads()
|
||||
{
|
||||
LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
|
||||
if (mActiveRecordings.empty()) return;
|
||||
|
||||
LLMutexLock lock(&mSlaveListMutex);
|
||||
|
||||
RecordingBuffers& target_recording_buffers = mActiveRecordings.front()->mPartialRecording;
|
||||
for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
// ignore block timing info for now
|
||||
(*it)->mSharedData.mergeTo(target_recording_buffers);
|
||||
(*it)->mSharedData.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child )
|
||||
{
|
||||
LLMutexLock lock(&mSlaveListMutex);
|
||||
|
||||
mSlaveThreadRecorders.push_back(child);
|
||||
}
|
||||
|
||||
void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child )
|
||||
{
|
||||
LLMutexLock lock(&mSlaveListMutex);
|
||||
|
||||
for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
|
||||
it != end_it;
|
||||
++it)
|
||||
{
|
||||
if ((*it) == child)
|
||||
{
|
||||
mSlaveThreadRecorders.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MasterThreadRecorder::pushToMaster()
|
||||
{}
|
||||
|
||||
MasterThreadRecorder::MasterThreadRecorder()
|
||||
{}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* @file lltrace.h
|
||||
* @brief Runtime statistics accumulation.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLTRACETHREADRECORDER_H
|
||||
#define LL_LLTRACETHREADRECORDER_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include "llmutex.h"
|
||||
#include "lltracerecording.h"
|
||||
|
||||
namespace LLTrace
|
||||
{
|
||||
class LL_COMMON_API ThreadRecorder
|
||||
{
|
||||
protected:
|
||||
struct ActiveRecording;
|
||||
typedef std::list<ActiveRecording*> active_recording_list_t;
|
||||
public:
|
||||
ThreadRecorder();
|
||||
|
||||
virtual ~ThreadRecorder();
|
||||
|
||||
void activate(Recording* recording);
|
||||
active_recording_list_t::iterator update(Recording* recording);
|
||||
void deactivate(Recording* recording);
|
||||
|
||||
virtual void pushToMaster() = 0;
|
||||
|
||||
TimeBlockTreeNode* getTimeBlockTreeNode(S32 index);
|
||||
|
||||
protected:
|
||||
struct ActiveRecording
|
||||
{
|
||||
ActiveRecording(Recording* target);
|
||||
|
||||
Recording* mTargetRecording;
|
||||
RecordingBuffers mPartialRecording;
|
||||
|
||||
void moveBaselineToTarget();
|
||||
};
|
||||
Recording mThreadRecording;
|
||||
|
||||
active_recording_list_t mActiveRecordings;
|
||||
|
||||
class BlockTimer* mRootTimer;
|
||||
TimeBlockTreeNode* mTimeBlockTreeNodes;
|
||||
size_t mNumTimeBlockTreeNodes;
|
||||
};
|
||||
|
||||
class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder
|
||||
{
|
||||
public:
|
||||
MasterThreadRecorder();
|
||||
|
||||
void addSlaveThread(class SlaveThreadRecorder* child);
|
||||
void removeSlaveThread(class SlaveThreadRecorder* child);
|
||||
|
||||
/*virtual */ void pushToMaster();
|
||||
|
||||
// call this periodically to gather stats data from slave threads
|
||||
void pullFromSlaveThreads();
|
||||
|
||||
LLMutex* getSlaveListMutex() { return &mSlaveListMutex; }
|
||||
|
||||
private:
|
||||
|
||||
typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t;
|
||||
|
||||
slave_thread_recorder_list_t mSlaveThreadRecorders;
|
||||
LLMutex mSlaveListMutex;
|
||||
};
|
||||
|
||||
class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder
|
||||
{
|
||||
public:
|
||||
SlaveThreadRecorder();
|
||||
~SlaveThreadRecorder();
|
||||
|
||||
// call this periodically to gather stats data for master thread to consume
|
||||
/*virtual*/ void pushToMaster();
|
||||
|
||||
MasterThreadRecorder* mMaster;
|
||||
|
||||
class SharedData
|
||||
{
|
||||
public:
|
||||
void appendFrom(const Recording& source);
|
||||
void appendTo(Recording& sink);
|
||||
void mergeFrom(const RecordingBuffers& source);
|
||||
void mergeTo(RecordingBuffers& sink);
|
||||
void reset();
|
||||
private:
|
||||
LLMutex mRecordingMutex;
|
||||
Recording mRecording;
|
||||
};
|
||||
SharedData mSharedData;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LL_LLTRACETHREADRECORDER_H
|
||||
|
|
@ -0,0 +1,476 @@
|
|||
/**
|
||||
* @file llunit.h
|
||||
* @brief Unit conversion classes
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2012, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLUNIT_H
|
||||
#define LL_LLUNIT_H
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
#include "llerrorlegacy.h"
|
||||
|
||||
namespace LLUnits
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct HighestPrecisionType
|
||||
{
|
||||
typedef T type_t;
|
||||
};
|
||||
|
||||
template<> struct HighestPrecisionType<F32> { typedef F64 type_t; };
|
||||
template<> struct HighestPrecisionType<S32> { typedef S64 type_t; };
|
||||
template<> struct HighestPrecisionType<U32> { typedef S64 type_t; };
|
||||
template<> struct HighestPrecisionType<S16> { typedef S64 type_t; };
|
||||
template<> struct HighestPrecisionType<U16> { typedef S64 type_t; };
|
||||
template<> struct HighestPrecisionType<S8> { typedef S64 type_t; };
|
||||
template<> struct HighestPrecisionType<U8> { typedef S64 type_t; };
|
||||
|
||||
template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE>
|
||||
struct ConversionFactor
|
||||
{
|
||||
static typename HighestPrecisionType<VALUE_TYPE>::type_t get()
|
||||
{
|
||||
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
|
||||
llstatic_assert_template(DERIVED_UNITS_TAG, false, "Cannot convert between types.");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename BASE_UNITS_TAG, typename VALUE_TYPE>
|
||||
struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE>
|
||||
{
|
||||
static typename HighestPrecisionType<VALUE_TYPE>::type_t get()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE>
|
||||
struct LLUnit
|
||||
{
|
||||
typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> self_t;
|
||||
typedef STORAGE_TYPE storage_t;
|
||||
|
||||
// value initialization
|
||||
LLUnit(storage_t value = storage_t())
|
||||
: mValue(value)
|
||||
{}
|
||||
|
||||
// unit initialization and conversion
|
||||
template<typename OTHER_UNIT, typename OTHER_STORAGE>
|
||||
LLUnit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
|
||||
: mValue(convert(other))
|
||||
{}
|
||||
|
||||
// value assignment
|
||||
self_t& operator = (storage_t value)
|
||||
{
|
||||
mValue = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// unit assignment
|
||||
template<typename OTHER_UNIT, typename OTHER_STORAGE>
|
||||
self_t& operator = (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
|
||||
{
|
||||
mValue = convert(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
storage_t value() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
template<typename NEW_UNIT_TYPE> LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE> as()
|
||||
{
|
||||
return LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE>(*this);
|
||||
}
|
||||
|
||||
|
||||
void operator += (storage_t value)
|
||||
{
|
||||
mValue += value;
|
||||
}
|
||||
|
||||
template<typename OTHER_UNIT, typename OTHER_STORAGE>
|
||||
void operator += (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
|
||||
{
|
||||
mValue += convert(other);
|
||||
}
|
||||
|
||||
void operator -= (storage_t value)
|
||||
{
|
||||
mValue -= value;
|
||||
}
|
||||
|
||||
template<typename OTHER_UNIT, typename OTHER_STORAGE>
|
||||
void operator -= (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
|
||||
{
|
||||
mValue -= convert(other);
|
||||
}
|
||||
|
||||
void operator *= (storage_t multiplicand)
|
||||
{
|
||||
mValue *= multiplicand;
|
||||
}
|
||||
|
||||
template<typename OTHER_UNIT, typename OTHER_STORAGE>
|
||||
void operator *= (LLUnit<OTHER_UNIT, OTHER_STORAGE> multiplicand)
|
||||
{
|
||||
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
|
||||
llstatic_assert_template(OTHER_UNIT, false, "Multiplication of unit types not supported.");
|
||||
}
|
||||
|
||||
void operator /= (storage_t divisor)
|
||||
{
|
||||
mValue /= divisor;
|
||||
}
|
||||
|
||||
template<typename OTHER_UNIT, typename OTHER_STORAGE>
|
||||
void operator /= (LLUnit<OTHER_UNIT, OTHER_STORAGE> divisor)
|
||||
{
|
||||
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
|
||||
llstatic_assert_template(OTHER_UNIT, 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)
|
||||
{
|
||||
return (storage_t)(v.value()
|
||||
* LLUnits::ConversionFactor<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t, SOURCE_STORAGE>::get()
|
||||
* LLUnits::ConversionFactor<typename UNIT_TYPE::base_unit_t, UNIT_TYPE, STORAGE_TYPE>::get());
|
||||
}
|
||||
|
||||
protected:
|
||||
storage_t mValue;
|
||||
};
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE>
|
||||
struct LLUnitImplicit : public LLUnit<UNIT_TYPE, STORAGE_TYPE>
|
||||
{
|
||||
typedef LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> self_t;
|
||||
typedef typename LLUnit<UNIT_TYPE, STORAGE_TYPE>::storage_t storage_t;
|
||||
typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> base_t;
|
||||
|
||||
LLUnitImplicit(storage_t value = storage_t())
|
||||
: base_t(value)
|
||||
{}
|
||||
|
||||
template<typename OTHER_UNIT, typename OTHER_STORAGE>
|
||||
LLUnitImplicit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
|
||||
: base_t(convert(other))
|
||||
{}
|
||||
|
||||
// unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD scalar (F32, S32, etc)
|
||||
// this allows for interoperability with legacy code
|
||||
operator storage_t() const
|
||||
{
|
||||
return base_t::value();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// operator +
|
||||
//
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
|
||||
{
|
||||
LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
|
||||
result += second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
|
||||
result += second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
|
||||
{
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
|
||||
result += second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
|
||||
{
|
||||
LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
|
||||
result += second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
|
||||
result += second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
|
||||
{
|
||||
LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
|
||||
result += second;
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// operator -
|
||||
//
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
|
||||
{
|
||||
LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
|
||||
result -= second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
|
||||
result -= second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
|
||||
{
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
|
||||
result -= second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
|
||||
{
|
||||
LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
|
||||
result -= second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
|
||||
result -= second;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second)
|
||||
{
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
|
||||
result -= second;
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// operator *
|
||||
//
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
|
||||
{
|
||||
return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first * second.value()));
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() * second));
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnit<UNIT_TYPE2, STORAGE_TYPE2>)
|
||||
{
|
||||
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
|
||||
llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported.");
|
||||
return LLUnit<UNIT_TYPE1, STORAGE_TYPE1>();
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second)
|
||||
{
|
||||
return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first * second.value());
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first.value() * second);
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2>)
|
||||
{
|
||||
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
|
||||
llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported.");
|
||||
return LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>();
|
||||
}
|
||||
|
||||
//
|
||||
// operator /
|
||||
//
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
|
||||
{
|
||||
return SCALAR_TYPE(first / second.value());
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second));
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
STORAGE_TYPE1 operator / (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
|
||||
{
|
||||
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
|
||||
return STORAGE_TYPE1(first.value() / second.value());
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
|
||||
LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
|
||||
{
|
||||
return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second));
|
||||
}
|
||||
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
|
||||
STORAGE_TYPE1 operator / (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
|
||||
{
|
||||
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
|
||||
return STORAGE_TYPE1(first.value() / second.value());
|
||||
}
|
||||
|
||||
#define COMPARISON_OPERATORS(op) \
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \
|
||||
bool operator op (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) \
|
||||
{ \
|
||||
return first op second.value(); \
|
||||
} \
|
||||
\
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \
|
||||
bool operator op (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) \
|
||||
{ \
|
||||
return first.value() op second; \
|
||||
} \
|
||||
\
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \
|
||||
bool operator op (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second) \
|
||||
{ \
|
||||
return first.value() op first.convert(second); \
|
||||
} \
|
||||
\
|
||||
template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \
|
||||
bool operator op (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) \
|
||||
{ \
|
||||
return first.value() op first.convert(second); \
|
||||
}
|
||||
|
||||
COMPARISON_OPERATORS(<)
|
||||
COMPARISON_OPERATORS(<=)
|
||||
COMPARISON_OPERATORS(>)
|
||||
COMPARISON_OPERATORS(>=)
|
||||
COMPARISON_OPERATORS(==)
|
||||
COMPARISON_OPERATORS(!=)
|
||||
|
||||
namespace LLUnits
|
||||
{
|
||||
template<typename T>
|
||||
T rawValue(T val) { return val; }
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE>
|
||||
STORAGE_TYPE rawValue(LLUnit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE>
|
||||
STORAGE_TYPE rawValue(LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
|
||||
|
||||
template<typename UNIT_TYPE, typename STORAGE_TYPE>
|
||||
struct HighestPrecisionType<LLUnit<UNIT_TYPE, STORAGE_TYPE> >
|
||||
{
|
||||
typedef typename HighestPrecisionType<STORAGE_TYPE>::type_t type_t;
|
||||
};
|
||||
|
||||
#define LL_DECLARE_DERIVED_UNIT(conversion_factor, base_unit_name, unit_name) \
|
||||
struct unit_name \
|
||||
{ \
|
||||
typedef base_unit_name base_unit_t; \
|
||||
}; \
|
||||
template<typename STORAGE_TYPE> \
|
||||
struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE> \
|
||||
{ \
|
||||
static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \
|
||||
{ \
|
||||
return typename HighestPrecisionType<STORAGE_TYPE>::type_t(conversion_factor); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template<typename STORAGE_TYPE> \
|
||||
struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \
|
||||
{ \
|
||||
static typename HighestPrecisionType<STORAGE_TYPE>::type_t get() \
|
||||
{ \
|
||||
return typename HighestPrecisionType<STORAGE_TYPE>::type_t(1.0 / (conversion_factor)); \
|
||||
} \
|
||||
}
|
||||
|
||||
struct Bytes { typedef Bytes base_unit_t; };
|
||||
LL_DECLARE_DERIVED_UNIT(1024, Bytes, Kilobytes);
|
||||
LL_DECLARE_DERIVED_UNIT(1024 * 1024, Bytes, Megabytes);
|
||||
LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024, Bytes, Gigabytes);
|
||||
LL_DECLARE_DERIVED_UNIT(1.0 / 8.0, Bytes, Bits);
|
||||
LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Kilobits);
|
||||
LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Megabits);
|
||||
LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024 / 8, Bytes, Gigabits);
|
||||
|
||||
struct Seconds { typedef Seconds base_unit_t; };
|
||||
LL_DECLARE_DERIVED_UNIT(60, Seconds, Minutes);
|
||||
LL_DECLARE_DERIVED_UNIT(60 * 60, Seconds, Hours);
|
||||
LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Seconds, Milliseconds);
|
||||
LL_DECLARE_DERIVED_UNIT(1.0 / 1000000.0, Seconds, Microseconds);
|
||||
LL_DECLARE_DERIVED_UNIT(1.0 / 1000000000.0, Seconds, Nanoseconds);
|
||||
|
||||
struct Meters { typedef Meters base_unit_t; };
|
||||
LL_DECLARE_DERIVED_UNIT(1000, Meters, Kilometers);
|
||||
LL_DECLARE_DERIVED_UNIT(1.0 / 100.0, Meters, Centimeters);
|
||||
LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Meters, Millimeters);
|
||||
|
||||
struct Hertz { typedef Hertz base_unit_t; };
|
||||
LL_DECLARE_DERIVED_UNIT(1000, Hertz, Kilohertz);
|
||||
LL_DECLARE_DERIVED_UNIT(1000 * 1000, Hertz, Megahertz);
|
||||
LL_DECLARE_DERIVED_UNIT(1000 * 1000 * 1000, Hertz, Gigahertz);
|
||||
} // namespace LLUnits
|
||||
|
||||
#endif // LL_LLUNIT_H
|
||||
|
|
@ -27,9 +27,7 @@
|
|||
|
||||
// We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes.
|
||||
#if LL_WINDOWS
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include "llwin32headers.h"
|
||||
// ugh, this is ugly. We need to straighten out our linking for this library
|
||||
#pragma comment(lib, "IPHLPAPI.lib")
|
||||
#include <iphlpapi.h>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* @file llwindows.h
|
||||
* @brief sanitized include of windows header files
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLWINDOWS_H
|
||||
#define LL_LLWINDOWS_H
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* @file llwindows.h
|
||||
* @brief sanitized include of windows header files
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLWINDOWS_H
|
||||
#define LL_LLWINDOWS_H
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#undef NOMINMAX
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -26,10 +26,11 @@
|
|||
#ifndef LL_LLWORKERTHREAD_H
|
||||
#define LL_LLWORKERTHREAD_H
|
||||
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "llqueuedthread.h"
|
||||
#include "llapr.h"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,208 @@
|
|||
/**
|
||||
* @file llsingleton_test.cpp
|
||||
* @date 2011-08-11
|
||||
* @brief Unit test for the LLSingleton class
|
||||
*
|
||||
* $LicenseInfo:firstyear=2011&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llunit.h"
|
||||
#include "../test/lltut.h"
|
||||
|
||||
namespace LLUnits
|
||||
{
|
||||
// using powers of 2 to allow strict floating point equality
|
||||
struct Quatloos { typedef Quatloos base_unit_t; };
|
||||
LL_DECLARE_DERIVED_UNIT(4, Quatloos, Latinum);
|
||||
LL_DECLARE_DERIVED_UNIT((1.0 / 4.0), Quatloos, Solari);
|
||||
}
|
||||
|
||||
namespace tut
|
||||
{
|
||||
using namespace LLUnits;
|
||||
struct units
|
||||
{
|
||||
};
|
||||
|
||||
typedef test_group<units> units_t;
|
||||
typedef units_t::object units_object_t;
|
||||
tut::units_t tut_singleton("LLUnit");
|
||||
|
||||
// storage type conversions
|
||||
template<> template<>
|
||||
void units_object_t::test<1>()
|
||||
{
|
||||
LLUnit<Quatloos, F32> float_quatloos;
|
||||
ensure(float_quatloos.value() == 0.f);
|
||||
|
||||
LLUnit<Quatloos, S32> int_quatloos;
|
||||
ensure(int_quatloos.value() == 0);
|
||||
|
||||
int_quatloos = 42;
|
||||
ensure(int_quatloos.value() == 42);
|
||||
float_quatloos = int_quatloos;
|
||||
ensure(float_quatloos.value() == 42.f);
|
||||
|
||||
int_quatloos = float_quatloos;
|
||||
ensure(int_quatloos.value() == 42);
|
||||
|
||||
float_quatloos = 42.1f;
|
||||
ensure(float_quatloos.value() == 42.1f);
|
||||
int_quatloos = float_quatloos;
|
||||
ensure(int_quatloos.value() == 42);
|
||||
LLUnit<Quatloos, U32> unsigned_int_quatloos(float_quatloos);
|
||||
ensure(unsigned_int_quatloos.value() == 42);
|
||||
}
|
||||
|
||||
// conversions to/from base unit
|
||||
template<> template<>
|
||||
void units_object_t::test<2>()
|
||||
{
|
||||
LLUnit<Quatloos, F32> quatloos(1.f);
|
||||
ensure(quatloos.value() == 1.f);
|
||||
LLUnit<Latinum, F32> latinum_bars(quatloos);
|
||||
ensure(latinum_bars.value() == 1.f / 4.f);
|
||||
|
||||
latinum_bars = 256;
|
||||
quatloos = latinum_bars;
|
||||
ensure(quatloos.value() == 1024);
|
||||
|
||||
LLUnit<Solari, F32> solari(quatloos);
|
||||
ensure(solari.value() == 4096);
|
||||
}
|
||||
|
||||
// conversions across non-base units
|
||||
template<> template<>
|
||||
void units_object_t::test<3>()
|
||||
{
|
||||
LLUnit<Solari, F32> solari = 4.f;
|
||||
LLUnit<Latinum, F32> latinum_bars = solari;
|
||||
ensure(latinum_bars.value() == 0.25f);
|
||||
}
|
||||
|
||||
// math operations
|
||||
template<> template<>
|
||||
void units_object_t::test<4>()
|
||||
{
|
||||
LLUnit<Quatloos, F32> quatloos = 1.f;
|
||||
quatloos *= 4.f;
|
||||
ensure(quatloos.value() == 4);
|
||||
quatloos = quatloos * 2;
|
||||
ensure(quatloos.value() == 8);
|
||||
quatloos = 2.f * quatloos;
|
||||
ensure(quatloos.value() == 16);
|
||||
|
||||
quatloos += 4.f;
|
||||
ensure(quatloos.value() == 20);
|
||||
quatloos += 4;
|
||||
ensure(quatloos.value() == 24);
|
||||
quatloos = quatloos + 4;
|
||||
ensure(quatloos.value() == 28);
|
||||
quatloos = 4 + quatloos;
|
||||
ensure(quatloos.value() == 32);
|
||||
quatloos += quatloos * 3;
|
||||
ensure(quatloos.value() == 128);
|
||||
|
||||
quatloos -= quatloos / 4 * 3;
|
||||
ensure(quatloos.value() == 32);
|
||||
quatloos = quatloos - 8;
|
||||
ensure(quatloos.value() == 24);
|
||||
quatloos -= 4;
|
||||
ensure(quatloos.value() == 20);
|
||||
quatloos -= 4.f;
|
||||
ensure(quatloos.value() == 16);
|
||||
|
||||
quatloos *= 2.f;
|
||||
ensure(quatloos.value() == 32);
|
||||
quatloos = quatloos * 2.f;
|
||||
ensure(quatloos.value() == 64);
|
||||
quatloos = 0.5f * quatloos;
|
||||
ensure(quatloos.value() == 32);
|
||||
|
||||
quatloos /= 2.f;
|
||||
ensure(quatloos.value() == 16);
|
||||
quatloos = quatloos / 4;
|
||||
ensure(quatloos.value() == 4);
|
||||
|
||||
F32 ratio = quatloos / LLUnit<Quatloos, F32>(4.f);
|
||||
ensure(ratio == 1);
|
||||
|
||||
quatloos += LLUnit<Solari, F32>(4.f);
|
||||
ensure(quatloos.value() == 5);
|
||||
quatloos -= LLUnit<Latinum, F32>(1.f);
|
||||
ensure(quatloos.value() == 1);
|
||||
}
|
||||
|
||||
// implicit units
|
||||
template<> template<>
|
||||
void units_object_t::test<5>()
|
||||
{
|
||||
// 0-initialized
|
||||
LLUnit<Quatloos, F32> quatloos(0);
|
||||
// initialize implicit unit from explicit
|
||||
LLUnitImplicit<Quatloos, F32> quatloos_implicit = quatloos + 1;
|
||||
ensure(quatloos_implicit.value() == 1);
|
||||
|
||||
// assign implicit to explicit, or perform math operations
|
||||
quatloos = quatloos_implicit;
|
||||
ensure(quatloos.value() == 1);
|
||||
quatloos += quatloos_implicit;
|
||||
ensure(quatloos.value() == 2);
|
||||
|
||||
// math operations on implicits
|
||||
quatloos_implicit = 1;
|
||||
ensure(quatloos_implicit == 1);
|
||||
|
||||
quatloos_implicit += 2;
|
||||
ensure(quatloos_implicit == 3);
|
||||
|
||||
quatloos_implicit *= 2;
|
||||
ensure(quatloos_implicit == 6);
|
||||
|
||||
quatloos_implicit -= 1;
|
||||
ensure(quatloos_implicit == 5);
|
||||
|
||||
quatloos_implicit /= 5;
|
||||
ensure(quatloos_implicit == 1);
|
||||
|
||||
quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit;
|
||||
ensure(quatloos_implicit == 5);
|
||||
|
||||
quatloos_implicit = 10 - quatloos_implicit - 1;
|
||||
ensure(quatloos_implicit == 4);
|
||||
|
||||
quatloos_implicit = 2 * quatloos_implicit * 2;
|
||||
ensure(quatloos_implicit == 16);
|
||||
|
||||
F32 one_half = quatloos_implicit / (quatloos_implicit * 2);
|
||||
ensure(one_half == 0.5f);
|
||||
|
||||
// implicit conversion to POD
|
||||
F32 float_val = quatloos_implicit;
|
||||
ensure(float_val == 16);
|
||||
|
||||
S32 int_val = quatloos_implicit;
|
||||
ensure(int_val == 16);
|
||||
}
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ private:
|
|||
|
||||
inline void RefCounted::addRef() const
|
||||
{
|
||||
S32 count(mRefCount++);
|
||||
S32 count(++mRefCount);
|
||||
llassert_always(count >= 0);
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ inline void RefCounted::release() const
|
|||
S32 count(mRefCount);
|
||||
llassert_always(count != NOT_REF_COUNTED);
|
||||
llassert_always(count > 0);
|
||||
count = mRefCount--;
|
||||
count = --mRefCount;
|
||||
|
||||
// clean ourselves up if that was the last reference
|
||||
if (0 == count)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ LLMutex* LLImage::sMutex = NULL;
|
|||
bool LLImage::sUseNewByteRange = false;
|
||||
S32 LLImage::sMinimalReverseByteRangePercent = 75;
|
||||
LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ;
|
||||
LLTrace::MemStatHandle LLImageBase::sMemStat("LLImage");
|
||||
|
||||
//static
|
||||
void LLImage::initClass(bool use_new_byte_range, S32 minimal_reverse_byte_range_percent)
|
||||
|
|
@ -158,6 +159,7 @@ void LLImageBase::sanityCheck()
|
|||
void LLImageBase::deleteData()
|
||||
{
|
||||
FREE_MEM(sPrivatePoolp, mData) ;
|
||||
memDisclaim(mDataSize);
|
||||
mData = NULL;
|
||||
mDataSize = 0;
|
||||
}
|
||||
|
|
@ -201,6 +203,7 @@ U8* LLImageBase::allocateData(S32 size)
|
|||
mBadBufferAllocation = true ;
|
||||
}
|
||||
mDataSize = size;
|
||||
memClaim(mDataSize);
|
||||
}
|
||||
|
||||
return mData;
|
||||
|
|
@ -222,7 +225,9 @@ U8* LLImageBase::reallocateData(S32 size)
|
|||
FREE_MEM(sPrivatePoolp, mData) ;
|
||||
}
|
||||
mData = new_datap;
|
||||
memDisclaim(mDataSize);
|
||||
mDataSize = size;
|
||||
memClaim(mDataSize);
|
||||
return mData;
|
||||
}
|
||||
|
||||
|
|
@ -288,7 +293,6 @@ LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components)
|
|||
LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components, bool no_copy)
|
||||
: LLImageBase()
|
||||
{
|
||||
|
||||
if(no_copy)
|
||||
{
|
||||
setDataAndSize(data, width, height, components);
|
||||
|
|
@ -1585,7 +1589,9 @@ static void avg4_colors2(const U8* a, const U8* b, const U8* c, const U8* d, U8*
|
|||
void LLImageBase::setDataAndSize(U8 *data, S32 size)
|
||||
{
|
||||
ll_assert_aligned(data, 16);
|
||||
memDisclaim(mDataSize);
|
||||
mData = data; mDataSize = size;
|
||||
memClaim(mDataSize);
|
||||
}
|
||||
|
||||
//static
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "lluuid.h"
|
||||
#include "llstring.h"
|
||||
#include "llthread.h"
|
||||
#include "lltrace.h"
|
||||
|
||||
const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2
|
||||
const S32 MAX_IMAGE_MIP = 11; // 2048x2048
|
||||
|
|
@ -110,7 +111,9 @@ protected:
|
|||
//============================================================================
|
||||
// Image base class
|
||||
|
||||
class LLImageBase : public LLThreadSafeRefCount
|
||||
class LLImageBase
|
||||
: public LLThreadSafeRefCount,
|
||||
public LLTrace::MemTrackable<LLImageBase>
|
||||
{
|
||||
protected:
|
||||
virtual ~LLImageBase();
|
||||
|
|
@ -162,6 +165,8 @@ public:
|
|||
static void destroyPrivatePool() ;
|
||||
static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;}
|
||||
|
||||
static LLTrace::MemStatHandle sMemStat;
|
||||
|
||||
private:
|
||||
U8 *mData;
|
||||
S32 mDataSize;
|
||||
|
|
@ -208,7 +213,7 @@ public:
|
|||
void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
|
||||
void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
|
||||
BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
|
||||
|
||||
|
||||
// Fill the buffer with a constant color
|
||||
void fill( const LLColor4U& color );
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#include "../llimageworker.h"
|
||||
// For timer class
|
||||
#include "../llcommon/lltimer.h"
|
||||
// for lltrace class
|
||||
#include "../llcommon/lltrace.h"
|
||||
// Tut header
|
||||
#include "../test/lltut.h"
|
||||
|
||||
|
|
@ -42,6 +44,9 @@
|
|||
// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
|
||||
// * A simulator for a class can be implemented here. Please comment and document thoroughly.
|
||||
|
||||
LLTrace::MemStatHandle LLImageBase::sMemStat("LLImage");
|
||||
|
||||
|
||||
LLImageBase::LLImageBase()
|
||||
: mData(NULL),
|
||||
mDataSize(0),
|
||||
|
|
@ -114,11 +119,13 @@ namespace tut
|
|||
// Constructor and destructor of the test wrapper
|
||||
imagedecodethread_test()
|
||||
{
|
||||
LLTrace::init();
|
||||
mThread = NULL;
|
||||
}
|
||||
~imagedecodethread_test()
|
||||
{
|
||||
delete mThread;
|
||||
LLTrace::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -136,6 +143,8 @@ namespace tut
|
|||
imagerequest_test()
|
||||
{
|
||||
done = false;
|
||||
LLTrace::init();
|
||||
|
||||
mRequest = new LLImageDecodeThread::ImageRequest(0, 0,
|
||||
LLQueuedThread::PRIORITY_NORMAL, 0, FALSE,
|
||||
new responder_test(&done));
|
||||
|
|
@ -145,6 +154,7 @@ namespace tut
|
|||
// We should delete the object *but*, because its destructor is protected, that cannot be
|
||||
// done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine...
|
||||
//delete mRequest;
|
||||
LLTrace::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#define LL_LLECONOMY_H
|
||||
|
||||
#include "llsingleton.h"
|
||||
#include <list>
|
||||
|
||||
class LLMessageSystem;
|
||||
class LLVector3;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "llinventory.h"
|
||||
|
||||
#include "lldbstrings.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llinventorydefines.h"
|
||||
#include "llxorcipher.h"
|
||||
#include "llsd.h"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@
|
|||
|
||||
// End Stubbing
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Stubb the LL Image Classes
|
||||
// Stub the LL Image Classes
|
||||
LLTrace::MemStatHandle LLImageBase::sMemStat("LLImage");
|
||||
|
||||
LLImageRaw::LLImageRaw() { }
|
||||
LLImageRaw::~LLImageRaw() { }
|
||||
U8* LLImageRaw::allocateData(S32 ) { return NULL; }
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
|
|||
|
||||
// ---------------- test methods ----------------
|
||||
|
||||
S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)
|
||||
S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius, const LLPlane* planes)
|
||||
{
|
||||
static const LLVector4a scaler[] = {
|
||||
LLVector4a(-1,-1,-1),
|
||||
|
|
@ -174,6 +174,12 @@ S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)
|
|||
LLVector4a( 1, 1, 1)
|
||||
};
|
||||
|
||||
if(!planes)
|
||||
{
|
||||
//use agent space
|
||||
planes = mAgentPlanes;
|
||||
}
|
||||
|
||||
U8 mask = 0;
|
||||
bool result = false;
|
||||
LLVector4a rscale, maxp, minp;
|
||||
|
|
@ -183,7 +189,7 @@ S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)
|
|||
mask = mPlaneMask[i];
|
||||
if (mask != 0xff)
|
||||
{
|
||||
const LLPlane& p(mAgentPlanes[i]);
|
||||
const LLPlane& p(planes[i]);
|
||||
p.getAt<3>(d);
|
||||
rscale.setMul(radius, scaler[mask]);
|
||||
minp.setSub(center, rscale);
|
||||
|
|
@ -204,8 +210,14 @@ S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)
|
|||
return result?1:2;
|
||||
}
|
||||
|
||||
//exactly same as the function AABBInFrustum(...)
|
||||
//except uses mRegionPlanes instead of mAgentPlanes.
|
||||
S32 LLCamera::AABBInRegionFrustum(const LLVector4a& center, const LLVector4a& radius)
|
||||
{
|
||||
return AABBInFrustum(center, radius, mRegionPlanes);
|
||||
}
|
||||
|
||||
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
|
||||
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius, const LLPlane* planes)
|
||||
{
|
||||
static const LLVector4a scaler[] = {
|
||||
LLVector4a(-1,-1,-1),
|
||||
|
|
@ -218,6 +230,12 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a&
|
|||
LLVector4a( 1, 1, 1)
|
||||
};
|
||||
|
||||
if(!planes)
|
||||
{
|
||||
//use agent space
|
||||
planes = mAgentPlanes;
|
||||
}
|
||||
|
||||
U8 mask = 0;
|
||||
bool result = false;
|
||||
LLVector4a rscale, maxp, minp;
|
||||
|
|
@ -227,7 +245,7 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a&
|
|||
mask = mPlaneMask[i];
|
||||
if ((i != 5) && (mask != 0xff))
|
||||
{
|
||||
const LLPlane& p(mAgentPlanes[i]);
|
||||
const LLPlane& p(planes[i]);
|
||||
p.getAt<3>(d);
|
||||
rscale.setMul(radius, scaler[mask]);
|
||||
minp.setSub(center, rscale);
|
||||
|
|
@ -248,6 +266,13 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a&
|
|||
return result?1:2;
|
||||
}
|
||||
|
||||
//exactly same as the function AABBInFrustumNoFarClip(...)
|
||||
//except uses mRegionPlanes instead of mAgentPlanes.
|
||||
S32 LLCamera::AABBInRegionFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
|
||||
{
|
||||
return AABBInFrustumNoFarClip(center, radius, mRegionPlanes);
|
||||
}
|
||||
|
||||
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
|
||||
{
|
||||
LLVector3 dist = sphere_center-mFrustCenter;
|
||||
|
|
@ -584,6 +609,23 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
|
|||
}
|
||||
}
|
||||
|
||||
//calculate regional planes from mAgentPlanes.
|
||||
//vector "shift" is the vector of the region origin in the agent space.
|
||||
void LLCamera::calcRegionFrustumPlanes(const LLVector3& shift)
|
||||
{
|
||||
F32 d;
|
||||
LLVector3 n;
|
||||
for(S32 i = 0 ; i < 7; i++)
|
||||
{
|
||||
if (mPlaneMask[i] != 0xff)
|
||||
{
|
||||
n.setVec(mAgentPlanes[i][0], mAgentPlanes[i][1], mAgentPlanes[i][2]);
|
||||
d = mAgentPlanes[i][3] - n * shift;
|
||||
mRegionPlanes[i].setVec(n, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom)
|
||||
{
|
||||
LLVector3 a, b, c;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ public:
|
|||
|
||||
private:
|
||||
LL_ALIGN_16(LLPlane mAgentPlanes[7]); //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
|
||||
LL_ALIGN_16(LLPlane mRegionPlanes[7]); //frustum planes in a local region space, derived from mAgentPlanes
|
||||
U8 mPlaneMask[8]; // 8 for alignment
|
||||
|
||||
F32 mView; // angle between top and bottom frustum planes in radians.
|
||||
|
|
@ -178,6 +179,7 @@ public:
|
|||
// Return number of bytes copied.
|
||||
size_t readFrustumFromBuffer(const char *buffer);
|
||||
void calcAgentFrustumPlanes(LLVector3* frust);
|
||||
void calcRegionFrustumPlanes(const LLVector3& shift); //calculate regional planes from mAgentPlanes.
|
||||
void ignoreAgentFrustumPlane(S32 idx);
|
||||
|
||||
// Returns 1 if partly in, 2 if fully in.
|
||||
|
|
@ -186,8 +188,10 @@ public:
|
|||
S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const;
|
||||
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
||||
S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); }
|
||||
S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
|
||||
S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
|
||||
S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius, const LLPlane* planes = NULL);
|
||||
S32 AABBInRegionFrustum(const LLVector4a& center, const LLVector4a& radius);
|
||||
S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius, const LLPlane* planes = NULL);
|
||||
S32 AABBInRegionFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
|
||||
|
||||
//does a quick 'n dirty sphere-sphere check
|
||||
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
|
||||
|
|
|
|||
|
|
@ -6066,12 +6066,13 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
|
|||
S32 max_t = volume->getPath().mPath.size();
|
||||
|
||||
// S32 i;
|
||||
S32 num_vertices = 0, num_indices = 0;
|
||||
//S32 num_vertices = 0;
|
||||
//S32 num_indices = 0;
|
||||
S32 grid_size = (profile.size()-1)/4;
|
||||
S32 quad_count = (grid_size * grid_size);
|
||||
//S32 quad_count = (grid_size * grid_size);
|
||||
|
||||
num_vertices = (grid_size+1)*(grid_size+1);
|
||||
num_indices = quad_count * 4;
|
||||
//num_vertices = (grid_size+1)*(grid_size+1);
|
||||
//num_indices = quad_count * 4;
|
||||
|
||||
LLVector4a& min = mExtents[0];
|
||||
LLVector4a& max = mExtents[1];
|
||||
|
|
|
|||
|
|
@ -49,10 +49,10 @@ class LLColor4
|
|||
LLColor4(); // Initializes LLColor4 to (0, 0, 0, 1)
|
||||
LLColor4(F32 r, F32 g, F32 b); // Initializes LLColor4 to (r, g, b, 1)
|
||||
LLColor4(F32 r, F32 g, F32 b, F32 a); // Initializes LLColor4 to (r. g, b, a)
|
||||
LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc))
|
||||
LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1)
|
||||
LLColor4(const LLColor3 &vec, F32 a = 1.f); // Initializes LLColor4 to (vec, a)
|
||||
explicit LLColor4(const LLSD& sd);
|
||||
explicit LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1)
|
||||
explicit LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc))
|
||||
explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion
|
||||
explicit LLColor4(const LLVector4& vector4); // "explicit" to avoid automatic conversion
|
||||
|
||||
|
|
|
|||
|
|
@ -50,10 +50,14 @@
|
|||
#include "lltransfertargetvfile.h" // For debugging
|
||||
|
||||
#include "llmetrics.h"
|
||||
#include "lltrace.h"
|
||||
|
||||
LLAssetStorage *gAssetStorage = NULL;
|
||||
LLMetrics *LLAssetStorage::metric_recipient = NULL;
|
||||
|
||||
static LLTrace::CountStatHandle<> sFailedDownloadCount("faileddownloads", "Number of times LLAssetStorage::getAssetData() has failed");
|
||||
|
||||
|
||||
const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-000000000010"));
|
||||
|
||||
const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000); // microseconds
|
||||
|
|
@ -450,6 +454,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
|
|||
|
||||
if (callback)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_FAILED, LL_EXSTAT_NONE);
|
||||
}
|
||||
return;
|
||||
|
|
@ -460,6 +465,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
|
|||
// Special case early out for NULL uuid and for shutting down
|
||||
if (callback)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
callback(mVFS, uuid, type, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
|
||||
}
|
||||
return;
|
||||
|
|
@ -572,6 +578,7 @@ void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType at
|
|||
llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
|
||||
if (callback)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
callback(mVFS, uuid, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
|
||||
}
|
||||
}
|
||||
|
|
@ -649,6 +656,10 @@ void LLAssetStorage::downloadCompleteCallback(
|
|||
LLAssetRequest* tmp = *curiter;
|
||||
if (tmp->mDownCallback)
|
||||
{
|
||||
if (result != LL_ERR_NOERR)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
}
|
||||
tmp->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), tmp->mUserData, result, ext_status);
|
||||
}
|
||||
delete tmp;
|
||||
|
|
@ -669,6 +680,7 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen
|
|||
// Special case early out for NULL uuid
|
||||
if (callback)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
callback(mVFS, asset_id, atype, user_data, LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE, LL_EXSTAT_NULL_UUID);
|
||||
}
|
||||
return;
|
||||
|
|
@ -741,6 +753,7 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen
|
|||
llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
|
||||
if (callback)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
|
||||
}
|
||||
}
|
||||
|
|
@ -783,6 +796,10 @@ void LLAssetStorage::downloadEstateAssetCompleteCallback(
|
|||
}
|
||||
}
|
||||
|
||||
if (result != LL_ERR_NOERR)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
}
|
||||
req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getAType(), req->mUserData, result, ext_status);
|
||||
}
|
||||
|
||||
|
|
@ -883,6 +900,7 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age
|
|||
llwarns << "Attempt to move asset data request upstream w/o valid upstream provider" << llendl;
|
||||
if (callback)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
callback(mVFS, asset_id, atype, user_data, LL_ERR_CIRCUIT_GONE, LL_EXSTAT_NO_UPSTREAM);
|
||||
}
|
||||
}
|
||||
|
|
@ -925,6 +943,10 @@ void LLAssetStorage::downloadInvItemCompleteCallback(
|
|||
}
|
||||
}
|
||||
|
||||
if (result != LL_ERR_NOERR)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
}
|
||||
req->mDownCallback(gAssetStorage->mVFS, req->getUUID(), req->getType(), req->mUserData, result, ext_status);
|
||||
}
|
||||
|
||||
|
|
@ -1237,6 +1259,7 @@ bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* re
|
|||
}
|
||||
if (req->mDownCallback)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
req->mDownCallback(mVFS, req->getUUID(), req->getType(), req->mUserData, error, LL_EXSTAT_REQUEST_DROPPED);
|
||||
}
|
||||
if (req->mInfoCallback)
|
||||
|
|
@ -1363,6 +1386,10 @@ void LLAssetStorage::legacyGetDataCallback(LLVFS *vfs, const LLUUID &uuid, LLAss
|
|||
}
|
||||
}
|
||||
|
||||
if (status != LL_ERR_NOERR)
|
||||
{
|
||||
add(sFailedDownloadCount, 1);
|
||||
}
|
||||
legacy->mDownCallback(filename.c_str(), uuid, legacy->mUserData, status, ext_status);
|
||||
delete legacy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "llmath.h"
|
||||
#include "llstl.h"
|
||||
#include "llthread.h"
|
||||
#include <iterator>
|
||||
|
||||
#define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED llassert(!mMutexp || mMutexp->isSelfLocked());
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "lldispatcher.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include "llstl.h"
|
||||
#include "message.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
|
||||
#include "llbuffer.h"
|
||||
#include "llbufferstream.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llmemorystream.h"
|
||||
#include "llsd.h"
|
||||
#include "llsdserialize.h"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "llapr.h"
|
||||
#include "llbuffer.h"
|
||||
#include "llbufferstream.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llhttpnode.h"
|
||||
#include "lliopipe.h"
|
||||
#include "lliosocket.h"
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "llwin32headerslean.h"
|
||||
#include "apr_poll.h"
|
||||
|
||||
#include "llsd.h"
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "llapr.h"
|
||||
|
||||
#include "llbuffer.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llhost.h"
|
||||
#include "llpumpio.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
*/
|
||||
|
||||
#include "lliopipe.h"
|
||||
#include "llwin32headerslean.h"
|
||||
#include "apr_pools.h"
|
||||
#include "apr_network_io.h"
|
||||
#include "llchainio.h"
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "linden_common.h"
|
||||
#include "llioutil.h"
|
||||
#include "llfasttimer.h"
|
||||
|
||||
/**
|
||||
* LLIOFlush
|
||||
|
|
|
|||
|
|
@ -29,12 +29,7 @@
|
|||
#include "llmail.h"
|
||||
|
||||
// APR on Windows needs full windows headers
|
||||
#ifdef LL_WINDOWS
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "llwin32headers.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
|
|
|
|||
|
|
@ -57,13 +57,15 @@ LLProxy::LLProxy():
|
|||
mAuthMethodSelected(METHOD_NOAUTH),
|
||||
mSocksUsername(),
|
||||
mSocksPassword()
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
LLProxy::~LLProxy()
|
||||
{
|
||||
stopSOCKSProxy();
|
||||
disableHTTPProxy();
|
||||
if (ll_apr_is_initialized())
|
||||
{
|
||||
stopSOCKSProxy();
|
||||
disableHTTPProxy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "apr_poll.h"
|
||||
|
||||
#include "llapr.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llstl.h"
|
||||
|
||||
// These should not be enabled in production, but they can be
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "llsdrpcclient.h"
|
||||
|
||||
#include "llbufferstream.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llfiltersd2xmlrpc.h"
|
||||
#include "llpumpio.h"
|
||||
#include "llsd.h"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue