merge with viewer-release

master
Richard Linden 2013-03-22 00:44:59 -07:00
commit 68f9f656cd
297 changed files with 13315 additions and 9024 deletions

View File

@ -58,6 +58,7 @@ if (WINDOWS)
add_definitions(
/DLL_WINDOWS=1
/DNOMINMAX
/DDOM_DYNAMIC
/DUNICODE
/D_UNICODE

View File

@ -40,6 +40,7 @@
#include "vorbis/codec.h"
#include "vorbis/vorbisfile.h"
#include <iterator>
extern LLAudioEngine *gAudiop;

View File

@ -30,6 +30,8 @@
#include "stdtypes.h" // from llcommon
#include <list>
#include "llstreamingaudio.h"
class LLAudioStreamManagerFMOD;

View File

@ -32,6 +32,7 @@
#include "llcharacter.h"
#include "llstring.h"
#include "llfasttimer.h"
#define SKEL_HEADER "Linden Skeleton 1.0"

View File

@ -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);

View File

@ -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");

View File

@ -31,6 +31,7 @@
// Header Files
//-----------------------------------------------------------------------------
#include <string>
#include <list>
#include "linked_lists.h"
#include "v3math.h"

View File

@ -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;

View File

@ -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);

View File

@ -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
{

View File

@ -30,6 +30,7 @@
#include "linden_common.h"
#include "llmotioncontroller.h"
#include "llfasttimer.h"
#include "llkeyframemotion.h"
#include "llmath.h"
#include "lltimer.h"

View File

@ -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");

View File

@ -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}")

View File

@ -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();

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -41,7 +41,6 @@
#include <algorithm>
// std headers
#include <typeinfo>
#include <cassert>
#include <cmath>
#include <cctype>
// external library headers

View File

@ -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

View File

@ -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

View File

@ -28,7 +28,7 @@
*/
#if LL_WINDOWS
#include <windows.h>
#include "llwin32headerslean.h"
#include <stdlib.h> // Windows errno
#else
#include <errno.h>

View File

@ -33,7 +33,7 @@
#include <ctype.h>
#ifdef WIN32
#include <windows.h>
#include "llwin32headers.h"
#include <winnt.h>
#endif

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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);

View File

@ -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

View File

@ -32,7 +32,6 @@
//#endif
#if defined(LL_WINDOWS)
//# include <windows.h>
# include <psapi.h>
#elif defined(LL_DARWIN)
# include <sys/types.h>

View File

@ -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*) );

View File

@ -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()

View File

@ -28,6 +28,7 @@
#define LLMORTICIAN_H
#include "stdtypes.h"
#include <list>
class LL_COMMON_API LLMortician
{

179
indra/llcommon/llmutex.cpp Normal file
View File

@ -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);
}
//============================================================================

101
indra/llcommon/llmutex.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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
};
}

View File

@ -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

View File

@ -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

View File

@ -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(); }

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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() {}
};

View File

@ -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;

View File

@ -32,7 +32,7 @@
#include <iostream>
#include <sstream>
#include "windows.h"
#include "llwin32headerslean.h"
#include "Dbghelp.h"
typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(

View File

@ -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;
}

View File

@ -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_

View File

@ -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,

View File

@ -31,6 +31,7 @@
#include <algorithm>
#include <map>
#include <vector>
#include <list>
#include <set>
#include <deque>
#include <typeinfo>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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()

View File

@ -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()
{

View File

@ -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;
}
}

View File

@ -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

View File

@ -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)

View File

@ -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

115
indra/llcommon/lltrace.cpp Normal file
View File

@ -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;
}
}

845
indra/llcommon/lltrace.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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()
{}
}

View File

@ -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

476
indra/llcommon/llunit.h Normal file
View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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

View File

@ -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 );

View File

@ -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();
}
};

View File

@ -27,6 +27,7 @@
#define LL_LLECONOMY_H
#include "llsingleton.h"
#include <list>
class LLMessageSystem;
class LLVector3;

View File

@ -28,6 +28,7 @@
#include "llinventory.h"
#include "lldbstrings.h"
#include "llfasttimer.h"
#include "llinventorydefines.h"
#include "llxorcipher.h"
#include "llsd.h"

View File

@ -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; }

View File

@ -161,7 +161,7 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
// ---------------- test methods ----------------
S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius, const LLPlane* planes)
{
static const LLVector4a scaler[] = {
LLVector4a(-1,-1,-1),
@ -174,6 +174,12 @@ S32 LLCamera::AABBInFrustum(const LLVector4a &center, 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 &center, 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 &center, 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;

View File

@ -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 &center, const F32 radius) const;
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
S32 sphereInFrustumFull(const LLVector3 &center, 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);

View File

@ -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];

View File

@ -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

View File

@ -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;
}

View File

@ -32,6 +32,7 @@
#include "llmath.h"
#include "llstl.h"
#include "llthread.h"
#include <iterator>
#define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED llassert(!mMutexp || mMutexp->isSelfLocked());

View File

@ -29,6 +29,7 @@
#include "lldispatcher.h"
#include <algorithm>
#include <iterator>
#include "llstl.h"
#include "message.h"

View File

@ -80,6 +80,7 @@
#include "llbuffer.h"
#include "llbufferstream.h"
#include "llfasttimer.h"
#include "llmemorystream.h"
#include "llsd.h"
#include "llsdserialize.h"

View File

@ -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"

View File

@ -31,6 +31,7 @@
#include <boost/intrusive_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include "llwin32headerslean.h"
#include "apr_poll.h"
#include "llsd.h"

View File

@ -32,6 +32,7 @@
#include "llapr.h"
#include "llbuffer.h"
#include "llfasttimer.h"
#include "llhost.h"
#include "llpumpio.h"

View File

@ -38,6 +38,7 @@
*/
#include "lliopipe.h"
#include "llwin32headerslean.h"
#include "apr_pools.h"
#include "apr_network_io.h"
#include "llchainio.h"

View File

@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llioutil.h"
#include "llfasttimer.h"
/**
* LLIOFlush

View File

@ -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>

View File

@ -57,13 +57,15 @@ LLProxy::LLProxy():
mAuthMethodSelected(METHOD_NOAUTH),
mSocksUsername(),
mSocksPassword()
{
}
{}
LLProxy::~LLProxy()
{
stopSOCKSProxy();
disableHTTPProxy();
if (ll_apr_is_initialized())
{
stopSOCKSProxy();
disableHTTPProxy();
}
}
/**

View File

@ -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

View File

@ -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