merge with release

master
Richard Linden 2013-06-20 16:46:23 -07:00
commit a2a6bf20d7
437 changed files with 16827 additions and 20705 deletions

View File

@ -74,4 +74,6 @@ glob:indra/newview/filters.xml
glob:indra/newview/avatar_icons_cache.txt
glob:indra/newview/avatar_lad.log
glob:*.diff
#*.rej
indra/newview/pilot.txt
indra/newview/pilot.xml
*.rej

View File

@ -498,9 +498,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>10352aab979c333a52dbad21b6e6fba9</string>
<string>10352aab979c333a52dbad21b6e6fba9</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274403/arch/Darwin/installer/fmodex-4.44-darwin-20130419.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274403/arch/Darwin/installer/fmodex-4.44-darwin-20130419.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
@ -510,7 +510,7 @@
<key>archive</key>
<map>
<key>hash</key>
<string>79e45527aa9fb90b813599dff5ce01a7</string>
<string>79e45527aa9fb90b813599dff5ce01a7</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274378/arch/Linux/installer/fmodex-4.44-linux-20130419.tar.bz2</string>
</map>
@ -762,9 +762,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>aff5566e04003de0383941981198e04e</string>
<string>aff5566e04003de0383941981198e04e</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
</map>
<key>name</key>
<string>darwin</string>
@ -776,7 +776,7 @@
<key>hash</key>
<string>52257e5eb166a0b69c9c0c38f6e1920e</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
@ -788,7 +788,7 @@
<key>hash</key>
<string>d812a6dfcabe6528198a3191068dac09</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/CYGWIN/installer/google_breakpad-0.0.0-rev1099-windows-20130329.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/CYGWIN/installer/google_breakpad-0.0.0-rev1099-windows-20130329.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -1326,9 +1326,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>5bc44db15eb3cca021382e40e04a9a38</string>
<string>9e5461d203b8259d3b6eb7df8c18b8fa</string>
<key>url</key>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-source/rev/271972/arch/Linux/installer/llappearanceutility_source-0.1-linux-20130315.tar.bz2</string>
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-interesting-source/rev/277616/arch/Linux/installer/llappearanceutility_source-0.1-linux-20130620.tar.bz2</string>
</map>
<key>name</key>
<string>linux</string>
@ -2567,7 +2567,7 @@
<string>"Visual Studio 10"</string>
<string>-DUNATTENDED:BOOL=ON</string>
<string>-DUSE_KDU=FALSE</string>
</array>
</array>
</map>
<key>name</key>
<string>DebugOS</string>
@ -2655,7 +2655,7 @@
<string>-DUNATTENDED:BOOL=ON</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string>
<string>-DUSE_KDU=FALSE</string>
</array>
</array>
</map>
<key>name</key>
<string>RelWithDebInfoOS</string>
@ -2742,7 +2742,7 @@
<string>-DUNATTENDED:BOOL=ON</string>
<string>-DINSTALL_PROPRIETARY=FALSE</string>
<string>-DUSE_KDU=FALSE</string>
</array>
</array>
</map>
<key>name</key>
<string>ReleaseOS</string>

View File

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

View File

@ -36,8 +36,8 @@
#include "llavatarappearancedefines.h"
#include "llavatarjointmesh.h"
#include "imageids.h"
#include "lldir.h"
#include "lldeleteutils.h"
#include "lldir.h"
#include "llpolymorph.h"
#include "llpolymesh.h"
#include "llpolyskeletaldistortion.h"

View File

@ -117,7 +117,6 @@ BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
//-----------------------------------------------------------------------------
BOOL LLAvatarJointMesh::sPipelineRender = FALSE;
EAvatarRenderPass LLAvatarJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE;
U32 LLAvatarJointMesh::sClothingMaskImageName = 0;
LLColor4 LLAvatarJointMesh::sClothingInnerColor;

View File

@ -82,7 +82,6 @@ public:
static BOOL sPipelineRender;
//RN: this is here for testing purposes
static U32 sClothingMaskImageName;
static EAvatarRenderPass sRenderPass;
static LLColor4 sClothingInnerColor;
public:

View File

@ -35,6 +35,7 @@
#include "llxmltree.h"
#include "llendianswizzle.h"
#include "llpolymesh.h"
#include "llfasttimer.h"
//#include "../tools/imdebug/imdebug.h"
@ -619,9 +620,9 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
LLVector4a& normalized_binormal = binormals[vert_index_mesh];
normalized_binormal.setCross3(norm, tangent);
normalized_binormal.setCross3(norm, tangent);
normalized_binormal.normalize3fast();
tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
}

View File

@ -29,18 +29,11 @@
//-----------------------------------------------------------------------------
#include "llpreprocessor.h"
#include "llerrorlegacy.h"
//#include "llcommon.h"
//#include "llmemory.h"
#include "llavatarappearance.h"
#include "llavatarjoint.h"
#include "llpolymorph.h"
//#include "llviewercontrol.h"
//#include "llxmltree.h"
//#include "llvoavatar.h"
#include "llwearable.h"
//#include "lldir.h"
//#include "llvolume.h"
//#include "llendianswizzle.h"
#include "llfasttimer.h"
#include "llpolyskeletaldistortion.h"

View File

@ -38,11 +38,13 @@
#include "llvfs.h"
#include "lltexlayerparams.h"
#include "lltexturemanagerbridge.h"
#include "lllocaltextureobject.h"
#include "../llui/llui.h"
#include "llwearable.h"
#include "llwearabledata.h"
#include "llvertexbuffer.h"
#include "llviewervisualparam.h"
#include "llfasttimer.h"
//#include "../tools/imdebug/imdebug.h"

View File

@ -35,6 +35,7 @@
#include "lltexturemanagerbridge.h"
#include "../llui/llui.h"
#include "llwearable.h"
#include "llfasttimer.h"
//-----------------------------------------------------------------------------
// LLTexLayerParam

View File

@ -32,12 +32,12 @@
#include "llpermissions.h"
#include "llsaleinfo.h"
#include "llwearabletype.h"
#include "lllocaltextureobject.h"
class LLMD5;
class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
class LLLocalTextureObject;
class LLAvatarAppearance;
// Abstract class.

View File

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

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<F32, LLUnits::Milliseconds>(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

@ -34,7 +34,6 @@
#include <map>
#include <deque>
#include "lluuidhashmap.h"
#include "llmotion.h"
#include "llpose.h"
#include "llframetimer.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

@ -75,8 +75,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
@ -90,7 +92,6 @@ set(llcommon_SOURCE_FILES
llsdutil.cpp
llsecondlifeurls.cpp
llsingleton.cpp
llstat.cpp
llstacktrace.cpp
llstreamqueue.cpp
llstreamtools.cpp
@ -98,14 +99,15 @@ 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
metaclass.cpp
metaproperty.cpp
reflective.cpp
timing.cpp
u64.cpp
)
@ -115,7 +117,6 @@ set(llcommon_HEADER_FILES
bitpack.h
ctype_workaround.h
doublelinkedlist.h
fix_macros.h
imageids.h
indra_constants.h
@ -129,7 +130,6 @@ set(llcommon_HEADER_FILES
llapp.h
llapr.h
llassettype.h
llassoclist.h
llavatarconstants.h
llbase32.h
llbase64.h
@ -143,18 +143,14 @@ set(llcommon_HEADER_FILES
llcriticaldamp.h
llcursortypes.h
lldarray.h
lldarrayptr.h
lldate.h
lldefs.h
lldependencies.h
lldeleteutils.h
lldepthstack.h
lldictionary.h
lldlinked.h
lldoubledispatch.h
lldqueueptr.h
llendianswizzle.h
llenum.h
llerror.h
llerrorcontrol.h
llerrorlegacy.h
@ -178,18 +174,15 @@ set(llcommon_HEADER_FILES
llhash.h
llheartbeat.h
llhttpstatuscodes.h
llindexedqueue.h
llinitparam.h
llinstancetracker.h
llkeythrottle.h
lllazy.h
llleap.h
llleaplistener.h
lllistenerwrapper.h
lllinkedqueue.h
llliveappconfig.h
lllivefile.h
lllocalidhashmap.h
lllog.h
lllslconstants.h
llmap.h
@ -199,15 +192,15 @@ 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
llprocessor.h
llptrskiplist.h
llptrskipmap.h
llptrto.h
llqueuedthread.h
llrand.h
@ -224,12 +217,7 @@ set(llcommon_HEADER_FILES
llsecondlifeurls.h
llsimplehash.h
llsingleton.h
llskiplist.h
llskipmap.h
llsortedvector.h
llstack.h
llstacktrace.h
llstat.h
llstatenums.h
llstl.h
llstreamqueue.h
@ -239,22 +227,21 @@ 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
llwin32headers.h
llwin32headerslean.h
llworkerthread.h
ll_template_cast.h
metaclass.h
metaclasst.h
metaproperty.h
metapropertyt.h
reflective.h
reflectivet.h
roles_constants.h
stdenums.h
stdtypes.h
@ -326,7 +313,6 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
@ -334,7 +320,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(reflection "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs};${BOOST_CONTEXT_LIBRARY}")

File diff suppressed because it is too large Load Diff

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
@ -54,11 +58,21 @@ void ll_init_apr()
{
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);

View File

@ -32,28 +32,34 @@
#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>
#include "llwin32headerslean.h"
#include "apr_thread_proc.h"
#include "apr_thread_mutex.h"
#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;
};
@ -257,18 +269,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

@ -1,296 +0,0 @@
/**
* @file llassoclist.h
* @brief LLAssocList class header file
*
* $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_LLASSOCLIST_H
#define LL_LLASSOCLIST_H
//------------------------------------------------------------------------
// LLAssocList is an associative list container class.
//
// The implementation is a single linked list.
// Both index and value objects are stored by value (not reference).
// If pointer values are specified for index and/or value, this
// container does NOT assume ownership of the referenced objects,
// and does NOT delete() them on removal or destruction of the container.
//
// Note that operations are generally not optimized, and may of them
// are O(n) complexity.
//------------------------------------------------------------------------
#include <iostream>
template<class INDEX_TYPE, class VALUE_TYPE>
class LLAssocList
{
private:
// internal list node type
class Node
{
public:
Node(const INDEX_TYPE &index, const VALUE_TYPE &value, Node *next)
{
mIndex = index;
mValue = value;
mNext = next;
}
~Node() { }
INDEX_TYPE mIndex;
VALUE_TYPE mValue;
Node *mNext;
};
// head of the linked list
Node *mHead;
public:
// Constructor
LLAssocList()
{
mHead = NULL;
}
// Destructor
~LLAssocList()
{
removeAll();
}
// Returns TRUE if list is empty.
BOOL isEmpty()
{
return (mHead == NULL);
}
// Returns the number of items in the list.
U32 length()
{
U32 count = 0;
for ( Node *node = mHead;
node;
node = node->mNext )
{
count++;
}
return count;
}
// Removes item with the specified index.
BOOL remove( const INDEX_TYPE &index )
{
if (!mHead)
return FALSE;
if (mHead->mIndex == index)
{
Node *node = mHead;
mHead = mHead->mNext;
delete node;
return TRUE;
}
for ( Node *prev = mHead;
prev->mNext;
prev = prev->mNext )
{
if (prev->mNext->mIndex == index)
{
Node *node = prev->mNext;
prev->mNext = prev->mNext->mNext;
delete node;
return TRUE;
}
}
return FALSE;
}
// Removes all items from the list.
void removeAll()
{
while ( mHead )
{
Node *node = mHead;
mHead = mHead->mNext;
delete node;
}
}
// Adds a new item to the head of the list,
// removing any existing item with same index.
void addToHead( const INDEX_TYPE &index, const VALUE_TYPE &value )
{
remove(index);
Node *node = new Node(index, value, mHead);
mHead = node;
}
// Adds a new item to the end of the list,
// removing any existing item with the same index.
void addToTail( const INDEX_TYPE &index, const VALUE_TYPE &value )
{
remove(index);
Node *node = new Node(index, value, NULL);
if (!mHead)
{
mHead = node;
return;
}
for ( Node *prev=mHead;
prev;
prev=prev->mNext )
{
if (!prev->mNext)
{
prev->mNext=node;
return;
}
}
}
// Sets the value of a specified index.
// If index does not exist, a new value will be added only if
// 'addIfNotFound' is set to TRUE.
// Returns TRUE if successful.
BOOL setValue( const INDEX_TYPE &index, const VALUE_TYPE &value, BOOL addIfNotFound=FALSE )
{
VALUE_TYPE *valueP = getValue(index);
if (valueP)
{
*valueP = value;
return TRUE;
}
if (!addIfNotFound)
return FALSE;
addToTail(index, value);
return TRUE;
}
// Sets the ith value in the list.
// A new value will NOT be addded, if the ith value does not exist.
// Returns TRUE if successful.
BOOL setValueAt( U32 i, const VALUE_TYPE &value )
{
VALUE_TYPE *valueP = getValueAt(i);
if (valueP)
{
*valueP = value;
return TRUE;
}
return FALSE;
}
// Returns a pointer to the value for the specified index,
// or NULL if no item found.
VALUE_TYPE *getValue( const INDEX_TYPE &index )
{
for ( Node *node = mHead;
node;
node = node->mNext )
{
if (node->mIndex == index)
return &node->mValue;
}
return NULL;
}
// Returns a pointer to the ith value in the list, or
// NULL if i is not valid.
VALUE_TYPE *getValueAt( U32 i )
{
U32 count = 0;
for ( Node *node = mHead;
node;
node = node->mNext )
{
if (count == i)
return &node->mValue;
count++;
}
return NULL;
}
// Returns a pointer to the index for the specified index,
// or NULL if no item found.
INDEX_TYPE *getIndex( const INDEX_TYPE &index )
{
for ( Node *node = mHead;
node;
node = node->mNext )
{
if (node->mIndex == index)
return &node->mIndex;
}
return NULL;
}
// Returns a pointer to the ith index in the list, or
// NULL if i is not valid.
INDEX_TYPE *getIndexAt( U32 i )
{
U32 count = 0;
for ( Node *node = mHead;
node;
node = node->mNext )
{
if (count == i)
return &node->mIndex;
count++;
}
return NULL;
}
// Returns a pointer to the value for the specified index,
// or NULL if no item found.
VALUE_TYPE *operator[](const INDEX_TYPE &index)
{
return getValue(index);
}
// Returns a pointer to the ith value in the list, or
// NULL if i is not valid.
VALUE_TYPE *operator[](U32 i)
{
return getValueAt(i);
}
// Prints the list contents to the specified stream.
friend std::ostream &operator<<( std::ostream &os, LLAssocList &map )
{
os << "{";
for ( Node *node = map.mHead;
node;
node = node->mNext )
{
os << "<" << node->mIndex << ", " << node->mValue << ">";
if (node->mNext)
os << ", ";
}
os << "}";
return os;
}
};
#endif // LL_LLASSOCLIST_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<F32, LLUnits::Seconds> 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<F32, LLUnits::Seconds> time_constant, bool use_cache = true);
protected:
template<typename T>
static T lerp(T a, T b, LLUnit<F32, LLUnits::Seconds> time_constant, bool use_cache = true)
{
F32 interpolant = getInterpolant(time_constant, use_cache);
return ((a * (1.f - interpolant))
+ (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<F64, LLUnits::Seconds> 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<F64, LLUnits::Seconds> 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

0
indra/llcommon/lldeleteutils.h Executable file → Normal file
View File

View File

@ -27,17 +27,20 @@
#ifndef LL_LLDEPTHSTACK_H
#define LL_LLDEPTHSTACK_H
#include "linked_lists.h"
#include "llstl.h"
template <class DATA_TYPE> class LLDepthStack
{
private:
LLLinkedList<DATA_TYPE> mStack;
std::deque<DATA_TYPE*> mStack;
U32 mCurrentDepth;
U32 mMaxDepth;
public:
LLDepthStack() : mCurrentDepth(0), mMaxDepth(0) {}
LLDepthStack()
: mCurrentDepth(0), mMaxDepth(0)
{}
~LLDepthStack() {}
void setDepth(U32 depth)
@ -54,24 +57,27 @@ public:
{
if (mCurrentDepth < mMaxDepth)
{
mStack.addData(data);
mStack.push_back(data);
mCurrentDepth++;
}
else
{
// the last item falls off stack and is deleted
mStack.getLastData();
mStack.deleteCurrentData();
mStack.addData(data);
if (!mStack.empty())
{
mStack.pop_front();
}
mStack.push_back(data);
}
}
DATA_TYPE *pop()
{
DATA_TYPE *tempp = mStack.getFirstData();
if (tempp)
DATA_TYPE *tempp = NULL;
if (!mStack.empty())
{
mStack.removeCurrentData();
tempp = mStack.back();
mStack.pop_back();
mCurrentDepth--;
}
return tempp;
@ -79,20 +85,20 @@ public:
DATA_TYPE *check()
{
DATA_TYPE *tempp = mStack.getFirstData();
return tempp;
return mStack.empty() ? NULL : mStack.back();
}
void deleteAllData()
{
mCurrentDepth = 0;
mStack.deleteAllData();
std::for_each(mStack.begin(), mStack.end(), DeletePointer());
mStack.clear();
}
void removeAllNodes()
{
mCurrentDepth = 0;
mStack.removeAllNodes();
mStack.clear();
}
};

View File

@ -1,93 +0,0 @@
/**
* @file lldlinked.h
* @brief Declaration of the LLDLinked class.
*
* $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_LLDLINKED_H
#define LL_LLDLINKED_H
template <class Type> class LLDLinked
{
LLDLinked* mNextp;
LLDLinked* mPrevp;
public:
Type* getNext() { return (Type*)mNextp; }
Type* getPrev() { return (Type*)mPrevp; }
Type* getFirst() { return (Type*)mNextp; }
void init()
{
mNextp = mPrevp = NULL;
}
void unlink()
{
if (mPrevp) mPrevp->mNextp = mNextp;
if (mNextp) mNextp->mPrevp = mPrevp;
}
LLDLinked() { mNextp = mPrevp = NULL; }
virtual ~LLDLinked() { unlink(); }
virtual void deleteAll()
{
Type *curp = getFirst();
while(curp)
{
Type *nextp = curp->getNext();
curp->unlink();
delete curp;
curp = nextp;
}
}
void relink(Type &after)
{
LLDLinked *afterp = (LLDLinked*)&after;
afterp->mPrevp = this;
mNextp = afterp;
}
virtual void append(Type& after)
{
LLDLinked *afterp = (LLDLinked*)&after;
afterp->mPrevp = this;
afterp->mNextp = mNextp;
if (mNextp) mNextp->mPrevp = afterp;
mNextp = afterp;
}
virtual void insert(Type& before)
{
LLDLinked *beforep = (LLDLinked*)&before;
beforep->mNextp = this;
beforep->mPrevp = mPrevp;
if (mPrevp) mPrevp->mNextp = beforep;
mPrevp = beforep;
}
virtual void put(Type& obj) { append(obj); }
};
#endif

View File

@ -1,352 +0,0 @@
/**
* @file lldqueueptr.h
* @brief LLDynamicQueuePtr declaration
*
* $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_LLDQUEUEPTR_H
#define LL_LLDQUEUEPTR_H
template <class Type>
class LLDynamicQueuePtr
{
public:
enum
{
OKAY = 0,
FAIL = -1
};
LLDynamicQueuePtr(const S32 size=8);
~LLDynamicQueuePtr();
void init();
void destroy();
void reset();
void reallocate(U32 newsize);
// ACCESSORS
const Type& get(const S32 index) const; // no bounds checking
Type& get(const S32 index); // no bounds checking
const Type& operator [] (const S32 index) const { return get(index); }
Type& operator [] (const S32 index) { return get(index); }
S32 find(const Type &obj) const;
S32 count() const { return (mLastObj >= mFirstObj ? mLastObj - mFirstObj : mLastObj + mMaxObj - mFirstObj); }
S32 getMax() const { return mMaxObj; }
S32 getFirst() const { return mFirstObj; }
S32 getLast () const { return mLastObj; }
// MANIPULATE
S32 push(const Type &obj); // add to end of Queue, returns index from start
S32 pull( Type &obj); // pull from Queue, returns index from start
S32 remove (S32 index); // remove by index
S32 removeObj(const Type &obj); // remove by object
protected:
S32 mFirstObj, mLastObj, mMaxObj;
Type* mMemory;
public:
void print()
{
/*
Convert this to llinfos if it's intended to be used - djs 08/30/02
printf("Printing from %d to %d (of %d): ",mFirstObj, mLastObj, mMaxObj);
if (mFirstObj <= mLastObj)
{
for (S32 i=mFirstObj;i<mLastObj;i++)
{
printf("%d ",mMemory[i]);
}
}
else
{
for (S32 i=mFirstObj;i<mMaxObj;i++)
{
printf("%d ",mMemory[i]);
}
for (i=0;i<mLastObj;i++)
{
printf("%d ",mMemory[i]);
}
}
printf("\n");
*/
}
};
//--------------------------------------------------------
// LLDynamicQueuePtrPtr implementation
//--------------------------------------------------------
template <class Type>
inline LLDynamicQueuePtr<Type>::LLDynamicQueuePtr(const S32 size)
{
init();
reallocate(size);
}
template <class Type>
inline LLDynamicQueuePtr<Type>::~LLDynamicQueuePtr()
{
destroy();
}
template <class Type>
inline void LLDynamicQueuePtr<Type>::init()
{
mFirstObj = 0;
mLastObj = 0;
mMaxObj = 0;
mMemory = NULL;
}
template <class Type>
inline void LLDynamicQueuePtr<Type>::reallocate(U32 newsize)
{
if (newsize)
{
if (mFirstObj > mLastObj && newsize > mMaxObj)
{
Type* new_memory = new Type[newsize];
llassert(new_memory);
S32 _count = count();
S32 i, m = 0;
for (i=mFirstObj; i < mMaxObj; i++)
{
new_memory[m++] = mMemory[i];
}
for (i=0; i <=mLastObj; i++)
{
new_memory[m++] = mMemory[i];
}
delete[] mMemory;
mMemory = new_memory;
mFirstObj = 0;
mLastObj = _count;
}
else
{
Type* new_memory = new Type[newsize];
llassert(new_memory);
S32 i, m = 0;
for (i=0; i < mLastObj; i++)
{
new_memory[m++] = mMemory[i];
}
delete[] mMemory;
mMemory = new_memory;
}
}
else if (mMemory)
{
delete[] mMemory;
mMemory = NULL;
}
mMaxObj = newsize;
}
template <class Type>
inline void LLDynamicQueuePtr<Type>::destroy()
{
reset();
delete[] mMemory;
mMemory = NULL;
}
template <class Type>
void LLDynamicQueuePtr<Type>::reset()
{
for (S32 i=0; i < mMaxObj; i++)
{
get(i) = NULL; // unrefs for pointers
}
mFirstObj = 0;
mLastObj = 0;
}
template <class Type>
inline S32 LLDynamicQueuePtr<Type>::find(const Type &obj) const
{
S32 i;
if (mFirstObj <= mLastObj)
{
for ( i = mFirstObj; i < mLastObj; i++ )
{
if (mMemory[i] == obj)
{
return i;
}
}
}
else
{
for ( i = mFirstObj; i < mMaxObj; i++ )
{
if (mMemory[i] == obj)
{
return i;
}
}
for ( i = 0; i < mLastObj; i++ )
{
if (mMemory[i] == obj)
{
return i;
}
}
}
return FAIL;
}
template <class Type>
inline S32 LLDynamicQueuePtr<Type>::remove(S32 i)
{
if (mFirstObj > mLastObj)
{
if (i >= mFirstObj && i < mMaxObj)
{
while( i > mFirstObj)
{
mMemory[i] = mMemory[i-1];
i--;
}
mMemory[mFirstObj] = NULL;
mFirstObj++;
if (mFirstObj >= mMaxObj) mFirstObj = 0;
return count();
}
else if (i < mLastObj && i >= 0)
{
while(i < mLastObj)
{
mMemory[i] = mMemory[i+1];
i++;
}
mMemory[mLastObj] = NULL;
mLastObj--;
if (mLastObj < 0) mLastObj = mMaxObj-1;
return count();
}
}
else if (i <= mLastObj && i >= mFirstObj)
{
while(i < mLastObj)
{
mMemory[i] = mMemory[i+1];
i++;
}
mMemory[mLastObj] = NULL;
mLastObj--;
if (mLastObj < 0) mLastObj = mMaxObj-1;
return count();
}
return FAIL;
}
template <class Type>
inline S32 LLDynamicQueuePtr<Type>::removeObj(const Type& obj)
{
S32 ind = find(obj);
if (ind >= 0)
{
return remove(ind);
}
return FAIL;
}
template <class Type>
inline S32 LLDynamicQueuePtr<Type>::push(const Type &obj)
{
if (mMaxObj - count() <= 1)
{
reallocate(mMaxObj * 2);
}
mMemory[mLastObj++] = obj;
if (mLastObj >= mMaxObj)
{
mLastObj = 0;
}
return count();
}
template <class Type>
inline S32 LLDynamicQueuePtr<Type>::pull(Type &obj)
{
obj = NULL;
if (count() < 1) return -1;
obj = mMemory[mFirstObj];
mMemory[mFirstObj] = NULL;
mFirstObj++;
if (mFirstObj >= mMaxObj)
{
mFirstObj = 0;
}
return count();
}
template <class Type>
inline const Type& LLDynamicQueuePtr<Type>::get(const S32 i) const
{
return mMemory[i];
}
template <class Type>
inline Type& LLDynamicQueuePtr<Type>::get(const S32 i)
{
return mMemory[i];
}
#endif // LL_LLDQUEUEPTR_H

View File

@ -1,78 +0,0 @@
/**
* @file llenum.h
* @author Tom Yedwab
* @brief Utility class for storing enum value <-> string lookup.
*
* $LicenseInfo:firstyear=2006&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_LLENUM_H
#define LL_LLENUM_H
class LLEnum
{
public:
typedef std::pair<const std::string, const U32> enum_t;
enum
{
UNDEFINED = 0xffffffff,
};
LLEnum(const enum_t values_array[], const U32 length)
{
for (U32 i=0; i<length; ++i)
{
mEnumMap.insert(values_array[i]);
if (values_array[i].second >= mEnumArray.size())
{
mEnumArray.resize(values_array[i].second+1);
}
mEnumArray[values_array[i].second] = values_array[i].first;
}
}
U32 operator[](std::string str)
{
std::map<const std::string, const U32>::iterator itor;
itor = mEnumMap.find(str);
if (itor != mEnumMap.end())
{
return itor->second;
}
return UNDEFINED;
}
const std::string operator[](U32 index)
{
if (index < mEnumArray.size())
{
return mEnumArray[index];
}
return "";
}
private:
std::map<const std::string, const U32> mEnumMap;
std::vector<std::string> mEnumArray;
};
#endif // LL_LLENUM_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 LL_STATIC_ASSERT(func, msg) static_assert(func, msg)
#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) static_assert(false, msg)
#else
#define LL_STATIC_ASSERT(func, msg) BOOST_STATIC_ASSERT(func)
#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && false);
#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))
{
mTimer.setCollapsed(!open);
}
TimeBlock& TimeBlock::getRootTimeBlock()
{
static TimeBlock root_timer("root", NULL);
return root_timer;
}
void TimeBlock::pushLog(LLSD log)
{
LLMutexLock lock(sLogLock);
sLogQueue.push(log);
}
void TimeBlock::setLogLock(LLMutex* lock)
{
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);
// we drop the low-order byte in our timers, so report a lower frequency
static LLUnit<U64, LLUnits::Hertz> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency();
return sCPUClockFrequency.value();
#else
// If we're not using RDTSC, each fasttimer tick is just a performance counter tick.
// Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency())
@ -197,270 +159,207 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
firstcall = false;
}
return sCPUClockFrequency.value();
#endif
return sCPUClockFrequency >> 8;
}
#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, TimeBlock* parent)
: TraceType<TimeBlockAccumulator>(name)
{
mCountHistory = new U32[HISTORY_NUM];
memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
mCallHistory = new U32[HISTORY_NUM];
memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
}
LLFastTimer::NamedTimer::~NamedTimer()
TimeBlockTreeNode& TimeBlock::getTreeNode() const
{
delete[] mCountHistory;
delete[] mCallHistory;
TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex());
llassert(nodep);
return *nodep;
}
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());
}
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)
void TimeBlock::bootstrapTimerTree()
{
llassert_always(parent != this);
llassert_always(parent != NULL);
if (mParent)
{
// subtract our accumulated from previous parent
for (S32 i = 0; i < HISTORY_NUM; i++)
for (LLInstanceTracker<TimeBlock>::instance_iter begin_it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(), it = begin_it;
it != end_it;
++it)
{
mParent->mCountHistory[i] -= mCountHistory[i];
}
TimeBlock& timer = *it;
if (&timer == &TimeBlock::getRootTimeBlock()) continue;
// 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())
// bootstrap tree construction by attaching to last timer to be on stack
// when this timer was called
if (timer.getParent() == &TimeBlock::getRootTimeBlock())
{
children.erase(found_it);
}
}
TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
mParent = parent;
if (parent)
if (accumulator->mLastCaller)
{
getFrameState().mParent = &parent->getFrameState();
parent->getChildren().push_back(this);
parent->mNeedsSorting = true;
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;
}
}
}
S32 LLFastTimer::NamedTimer::getDepth()
// bump timers up tree if they have been flagged as being in the wrong place
// do this in a bottom up order to promote descendants first before promoting ancestors
// this preserves partial order derived from current frame's observations
void TimeBlock::incrementalUpdateTimerTree()
{
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()
{
if (sCurFrameIndex < 0 ) return;
// set up initial tree
{
for (instance_iter it = beginInstances(); it != endInstances(); ++it)
{
NamedTimer& timer = *it;
if (&timer == NamedTimerFactory::instance().getRootTimer()) 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())
{
timer.setParent(timer.getFrameState().mLastCaller->mTimer);
// no need to push up tree on first use, flag can be set spuriously
timer.getFrameState().mMoveUpTree = false;
}
}
}
// bump timers up tree if they've 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)
{
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, reparenting won't affect tree traversal
// 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();
++it)
{
NamedTimer* timerp = (*it);
if (timerp->mNeedsSorting)
{
std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
}
timerp->mNeedsSorting = false;
}
}
//static
void LLFastTimer::NamedTimer::accumulateTimings()
{
U32 cur_time = getCPUClockCount32();
void TimeBlock::updateTimes()
{
U64 cur_time = getCPUClockCount64();
// 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;
BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();
BlockTimer* cur_timer = stack_record->mActiveTimer;
TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
while(cur_timer
&& cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self
{
U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
accumulator->mTotalTimeCounter += cumulative_time_delta
- (accumulator->mTotalTimeCounter
- cur_timer->mBlockStartTotalTimeCounter);
accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime;
stack_record->mChildTime = 0;
cur_timer->mStartTime = cur_time;
cur_timer->mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;
cur_data = &cur_timer->mLastTimerData;
cur_data->mChildTime += cumulative_time_delta;
stack_record = &cur_timer->mParentTimerData;
accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
cur_timer = stack_record->mActiveTimer;
cur_timer = cur_timer->mLastTimerData.mCurTimer;
stack_record->mChildTime += cumulative_time_delta;
}
}
// 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();
static LLFastTimer::DeclareTimer FTM_PROCESS_TIMES("Process FastTimer Times");
// not thread safe, so only call on main thread
//static
void TimeBlock::processTimes()
{
LLFastTimer _(FTM_PROCESS_TIMES);
get_clock_count(); // good place to calculate clock frequency
// set up initial tree
bootstrapTimerTree();
incrementalUpdateTimerTree();
updateTimes();
// reset for next frame
for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
end_it = LLInstanceTracker<TimeBlock>::endInstances();
it != end_it;
++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;
}
TimeBlock& timer = *it;
TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
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);
}
accumulator->mLastCaller = NULL;
accumulator->mMoveUpTree = false;
}
}
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()
{
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<F64, LLUnits::Hertz>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;
}
call_count++;
F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
F64 total_time = 0;
LLUnit<F64, LLUnits::Seconds> 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.getLastRecording().getSum(timer).value());
sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().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.getLastRecording().getSum(timer);
}
}
sd["Total"]["Time"] = (LLSD::Real) total_time;
sd["Total"]["Time"] = (LLSD::Real) total_time.value();
sd["Total"]["Calls"] = (LLSD::Integer) 1;
{
@ -469,168 +368,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()
{
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)
void TimeBlock::dumpCurTimes()
{
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
LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer()
{
return *NamedTimerFactory::instance().getRootTimer();
}
//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.getLastRecording();
// 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<F64, LLUnits::Seconds> total_time = last_frame_recording.getSum(*timerp);
U32 num_calls = last_frame_recording.getSum(timerp->callCount());
// Don't bother with really brief times, keep output concise
if (total_time_ms < 0.1) continue;
if (total_time < LLUnit<F32, LLUnits::Milliseconds>(0.1)) continue;
std::ostringstream out_str;
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.getAs<LLUnits::Milliseconds>() << " 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())
{
@ -641,22 +416,62 @@ 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, bool append )
{
return NamedTimerFactory::instance().getTimerByName(name);
// we can't merge two unrelated time block samples, as that will screw with the nested timings
// due to the call hierarchy of each thread
llassert(append);
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<F64, LLUnits::Seconds> BlockTimer::getElapsedTime()
{
U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
return (F64)total_time / (F64)TimeBlock::countsPerSecond();
}
} // namespace LLTrace

View File

@ -28,216 +28,96 @@
#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<F64, LLUnits::Seconds> 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;
static NamedTimer& getRootNamedTimer();
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, TimeBlock* parent = &getRootTimeBlock());
LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
: mFrameState(&timer.mFrameState)
TimeBlockTreeNode& getTreeNode() const;
TimeBlock* getParent() const { return getTreeNode().getParent(); }
void setParent(TimeBlock* parent) { getTreeNode().setParent(parent); }
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();
TraceType<TimeBlockAccumulator::CallCountFacet>& callCount()
{
#if FAST_TIMER_ON
LLFastTimer::FrameState* frame_state = mFrameState;
mStartTime = getCPUClockCount32();
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);
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
return static_cast<TraceType<TimeBlockAccumulator::CallCountFacet>&>(*(TraceType<TimeBlockAccumulator>*)this);
}
LL_FORCE_INLINE ~LLFastTimer()
TraceType<TimeBlockAccumulator::SelfTimeFacet>& selfTime()
{
#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
return static_cast<TraceType<TimeBlockAccumulator::SelfTimeFacet>&>(*(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);
static void updateTimes();
// 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!
@ -260,14 +140,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();
//}
@ -307,7 +187,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()
{
@ -374,18 +254,74 @@ 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;
static void bootstrapTimerTree();
static void incrementalUpdateTimerTree();
// 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
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;
mStartTime = TimeBlock::getCPUClockCount64();
#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>
@ -438,7 +438,7 @@ llstdio_filebuf::int_type llstdio_filebuf::overflow(llstdio_filebuf::int_type __
_M_set_buffer(0);
__ret = traits_type::not_eof(__c);
}
}
}
else if (_M_buf_size > 1)
{
// Overflow in 'uncommitted' mode: set _M_writing, set
@ -496,11 +496,11 @@ bool llstdio_filebuf::_convert_to_external(char_type* __ibuf,
if (__r == codecvt_base::ok || __r == codecvt_base::partial)
__blen = __bend - __buf;
else if (__r == codecvt_base::noconv)
{
{
// Same as the always_noconv case above.
__buf = reinterpret_cast<char*>(__ibuf);
__blen = __ilen;
}
}
else
__throw_ios_failure(__N("llstdio_filebuf::_convert_to_external "
"conversion error"));
@ -643,9 +643,9 @@ llstdio_filebuf::int_type llstdio_filebuf::underflow()
_M_ext_end, _M_ext_next,
this->eback(),
this->eback() + __buflen, __iend);
}
}
if (__r == codecvt_base::noconv)
{
{
size_t __avail = _M_ext_end - _M_ext_buf;
__ilen = std::min(__avail, __buflen);
traits_type::copy(this->eback(),
@ -806,15 +806,15 @@ std::streamsize llstdio_filebuf::xsputn(char_type* __s, std::streamsize __n)
__ret = fwrite(__buf, 1, __buffill, _M_file.file());
}
if (__ret == __buffill)
{
{
__ret += fwrite(reinterpret_cast<const char*>(__s), 1,
__n, _M_file.file());
}
}
if (__ret == __buffill + __n)
{
_M_set_buffer(0);
_M_writing = true;
}
}
if (__ret > __buffill)
__ret -= __buffill;
else
@ -848,7 +848,7 @@ llifstream::llifstream() : _M_filebuf(),
#endif
// explicit
llifstream::llifstream(const std::string& _Filename,
llifstream::llifstream(const std::string& _Filename,
ios_base::openmode _Mode) : _M_filebuf(),
#if LL_WINDOWS
std::istream(&_M_filebuf)
@ -877,7 +877,7 @@ llifstream::llifstream(const char* _Filename,
if (_M_filebuf.open(wideName.c_str(), _Mode | ios_base::in) == 0)
{
_Myios::setstate(ios_base::failbit);
}
}
}
#else
std::istream()
@ -951,8 +951,8 @@ void llifstream::close()
#else
this->setstate(ios_base::failbit);
#endif
}
}
}
/************** output file stream ********************************/
@ -1042,7 +1042,7 @@ void llofstream::open(const char* _Filename, ios_base::openmode _Mode)
#if LL_WINDOWS
llutf16string wideName = utf8str_to_utf16str( _Filename );
if (_M_filebuf.open( wideName.c_str(), _Mode | ios_base::out) == 0)
{
{
_Myios::setstate(ios_base::failbit);
}
else

View File

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

View File

@ -1,155 +0,0 @@
/**
* @file llindexedqueue.h
* @brief An indexed FIFO queue, where only one element with each key
* can be in the queue.
*
* $LicenseInfo:firstyear=2003&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_LLINDEXEDQUEUE_H
#define LL_LLINDEXEDQUEUE_H
// An indexed FIFO queue, where only one element with each key can be in the queue.
// This is ONLY used in the interest list, you'll probably want to review this code
// carefully if you want to use it elsewhere - Doug
template <typename Type>
class LLIndexedQueue
{
protected:
typedef std::deque<Type> type_deque;
type_deque mQueue;
std::set<Type> mKeySet;
public:
LLIndexedQueue() {}
// move_if_there is an O(n) operation
bool push_back(const Type &value, bool move_if_there = false)
{
if (mKeySet.find(value) != mKeySet.end())
{
// Already on the queue
if (move_if_there)
{
// Remove the existing entry.
typename type_deque::iterator it;
for (it = mQueue.begin(); it != mQueue.end(); ++it)
{
if (*it == value)
{
break;
}
}
// This HAS to succeed, otherwise there's a serious bug in the keyset implementation
// (although this isn't thread safe, at all)
mQueue.erase(it);
}
else
{
// We're not moving it, leave it alone
return false;
}
}
else
{
// Doesn't exist, add it to the key set
mKeySet.insert(value);
}
mQueue.push_back(value);
// We succeeded in adding the new element.
return true;
}
bool push_front(const Type &value, bool move_if_there = false)
{
if (mKeySet.find(value) != mKeySet.end())
{
// Already on the queue
if (move_if_there)
{
// Remove the existing entry.
typename type_deque::iterator it;
for (it = mQueue.begin(); it != mQueue.end(); ++it)
{
if (*it == value)
{
break;
}
}
// This HAS to succeed, otherwise there's a serious bug in the keyset implementation
// (although this isn't thread safe, at all)
mQueue.erase(it);
}
else
{
// We're not moving it, leave it alone
return false;
}
}
else
{
// Doesn't exist, add it to the key set
mKeySet.insert(value);
}
mQueue.push_front(value);
return true;
}
void pop()
{
Type value = mQueue.front();
mKeySet.erase(value);
mQueue.pop_front();
}
Type &front()
{
return mQueue.front();
}
S32 size() const
{
return mQueue.size();
}
bool empty() const
{
return mQueue.empty();
}
void clear()
{
// Clear out all elements on the queue
mQueue.clear();
mKeySet.clear();
}
};
#endif // LL_LLINDEXEDQUEUE_H

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
//
@ -196,6 +203,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)
{
@ -209,11 +219,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();
@ -225,10 +242,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;
serialize_func(*param, parser, name_stack, diff_param);
serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param);
}
}
@ -239,7 +256,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.
@ -264,10 +281,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

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 LLTypeTags
{
@ -195,6 +196,8 @@ namespace LLInitParam
return mValue;
}
bool isValid() const { return true; }
protected:
T mValue;
};
@ -209,13 +212,11 @@ namespace LLInitParam
typedef T value_t;
ParamValue()
: T(),
mValidated(false)
: T()
{}
ParamValue(const default_value_t& other)
: T(other),
mValidated(false)
: T(other)
{}
void setValue(const value_t& val)
@ -232,9 +233,6 @@ namespace LLInitParam
{
return *this;
}
protected:
mutable bool mValidated; // lazy validation flag
};
@ -497,25 +495,25 @@ namespace LLInitParam
virtual ~Parser();
template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0)
{
{
parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
if (found_it != mParserReadFuncs->end())
{
{
return found_it->second(*this, (void*)&param);
}
return false;
}
return false;
}
template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0)
{
{
parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
if (found_it != mParserReadFuncs->end())
{
{
return found_it->second(*this, (void*)&param);
}
}
else
{
{
found_it = mParserReadFuncs->find(&typeid(S32));
if (found_it != mParserReadFuncs->end())
{
@ -579,6 +577,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
{
@ -589,7 +600,7 @@ namespace LLInitParam
typedef bool(*merge_func_t)(Param&, const Param&, bool);
typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool);
typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);
typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param);
typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count);
typedef bool(*validation_func_t)(const Param*);
@ -617,7 +628,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
@ -829,12 +840,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;
@ -852,10 +879,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 getBlockDescriptor(); }
@ -893,6 +929,9 @@ namespace LLInitParam
return mergeBlock(block_data, source, overwrite);
}
mutable bool mValidated; // lazy validation flag
bool mParamProvided;
private:
const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
};
@ -986,6 +1025,8 @@ namespace LLInitParam
bool isProvided() const { return Param::anyProvided(); }
bool isValid() const { return true; }
static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
self_t& typed_param = static_cast<self_t&>(param);
@ -1014,10 +1055,23 @@ 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()) 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())
{
@ -1030,25 +1084,27 @@ 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 (calculated_key.size()
&& (!diff_param
&& (!diff_typed_param
|| !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_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)
@ -1113,19 +1169,19 @@ namespace LLInitParam
};
// parameter that is a block
template <typename T, typename NAME_VALUE_LOOKUP>
class TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK>
template <typename BLOCK_T, typename NAME_VALUE_LOOKUP>
class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK>
: public Param,
public NAME_VALUE_LOOKUP::type_value_t
{
protected:
typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
typedef typename param_value_t::default_value_t default_value_t;
typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t;
typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
typedef ParamValue<typename LLTypeTags::Sorted<BLOCK_T>::value_t> param_value_t;
typedef typename param_value_t::default_value_t default_value_t;
typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t;
typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
public:
using named_value_t::operator();
typedef typename param_value_t::value_t value_t;
typedef typename param_value_t::value_t value_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr),
@ -1148,11 +1204,11 @@ namespace LLInitParam
if(named_value_t::valueNamesExist()
&& parser.readValue(name)
&& named_value_t::getValueFromName(name, typed_param.getValue()))
{
typed_param.setValueName(name);
typed_param.setProvided();
return true;
}
{
typed_param.setValueName(name);
typed_param.setProvided();
return true;
}
}
if(typed_param.deserializeBlock(parser, name_stack_range, new_name))
@ -1166,10 +1222,16 @@ 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)
{
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())
{
@ -1182,12 +1244,15 @@ namespace LLInitParam
if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
{
parser.writeValue(key, name_stack);
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)
@ -1209,13 +1274,12 @@ 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();
}
bool isValid() const
{
return param_value_t::isValid();
}
// assign block contents to this param-that-is-a-block
@ -1223,9 +1287,6 @@ namespace LLInitParam
{
setValue(val);
named_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);
}
@ -1242,9 +1303,6 @@ namespace LLInitParam
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();
named_value_t::clearValueName();
}
@ -1296,13 +1354,13 @@ namespace LLInitParam
};
// list of non-block parameters
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK>
template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP>
class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK>
: public Param
{
protected:
typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t;
typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t;
typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t;
typedef ParamValue<typename LLTypeTags::Sorted<MULTI_VALUE_T>::value_t> param_value_t;
typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
typedef container_t default_value_t;
typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
@ -1311,7 +1369,9 @@ namespace LLInitParam
typedef typename param_value_t::value_t value_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_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));
@ -1322,7 +1382,13 @@ 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, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
@ -1337,7 +1403,7 @@ namespace LLInitParam
}
// 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;
@ -1359,10 +1425,19 @@ 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()) 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;
@ -1378,7 +1453,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;
}
@ -1386,19 +1465,23 @@ namespace LLInitParam
}
else
{
if(!parser.writeValue(key, name_stack))
if(parser.writeValue(key, name_stack))
{
serialized = true;
}
else
{
break;
}
}
name_stack.pop_back();
}
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 (named_value_t::getPossibleValues())
{
parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
@ -1453,7 +1536,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();
}
@ -1483,6 +1566,8 @@ namespace LLInitParam
}
container_t mValues;
size_t mMinCount,
mMaxCount;
private:
void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
@ -1500,13 +1585,13 @@ namespace LLInitParam
};
// list of block parameters
template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP>
class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>
template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP>
class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>
: public Param
{
protected:
typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t;
typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t;
typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t;
typedef ParamValue<typename LLTypeTags::Sorted<MULTI_BLOCK_T>::value_t> param_value_t;
typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
typedef container_t default_value_t;
@ -1516,7 +1601,9 @@ namespace LLInitParam
typedef typename param_value_t::value_t value_t;
TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_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));
@ -1526,7 +1613,14 @@ 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, Parser::name_stack_range_t& name_stack_range, bool new_name)
{
@ -1549,7 +1643,7 @@ 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;
@ -1559,6 +1653,10 @@ namespace LLInitParam
{
typed_param.mValues.back().setValueName(name);
typed_param.setProvided();
if (new_array_value)
{
name_stack_range.first->second = false;
}
return true;
}
}
@ -1583,10 +1681,18 @@ 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()) 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;
@ -1597,17 +1703,24 @@ namespace LLInitParam
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)
@ -1670,14 +1783,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;
}
@ -1709,6 +1822,8 @@ namespace LLInitParam
}
container_t mValues;
size_t mMinCount,
mMaxCount;
private:
void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
@ -2015,7 +2130,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;
}
};
@ -2158,13 +2273,11 @@ namespace LLInitParam
typedef T default_value_t;
ParamValue()
: mValue(),
mValidated(false)
: mValue()
{}
ParamValue(const default_value_t& value)
: mValue(value),
mValidated(false)
: mValue(value)
{}
void setValue(const value_t& val)
@ -2191,18 +2304,18 @@ namespace LLInitParam
return mValue.deserializeBlock(p, name_stack_range, new_name);
}
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const
{
const BaseBlock* base_block = diff_block
? &(diff_block->mValue)
: NULL;
mValue.serializeBlock(p, name_stack, base_block);
return mValue.serializeBlock(p, name_stack, predicate_rule, base_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
{
{
return mValue.inspectBlock(p, name_stack, min_count, max_count);
}
}
bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
{
@ -2212,9 +2325,7 @@ namespace LLInitParam
// clear away what is there and take the new stuff as a whole
resetToDefault();
return mValue.mergeBlock(block_data, source.getValue(), overwrite);
}
}
return mValue.mergeBlock(block_data, source.getValue(), overwrite);
}
@ -2223,14 +2334,17 @@ namespace LLInitParam
return mValue.validateBlock(emit_errors);
}
bool isValid() const
{
return validateBlock(false);
}
static BlockDescriptor& getBlockDescriptor()
{
return value_t::getBlockDescriptor();
}
mutable bool mValidated; // lazy validation flag
private:
void resetToDefault()
{
@ -2251,15 +2365,13 @@ namespace LLInitParam
typedef T default_value_t;
ParamValue()
: mValue(),
mValidated(false)
: mValue()
{
mCurParam = getBlockDescriptor().mAllParams.begin();
}
ParamValue(const default_value_t& value)
: mValue(value),
mValidated(false)
: mValue(value)
{
mCurParam = getBlockDescriptor().mAllParams.begin();
}
@ -2284,7 +2396,7 @@ namespace LLInitParam
if (new_name)
{
mCurParam = getBlockDescriptor().mAllParams.begin();
}
}
if (name_stack_range.first == name_stack_range.second
&& mCurParam != getBlockDescriptor().mAllParams.end())
{
@ -2296,7 +2408,7 @@ namespace LLInitParam
if (deserialize_func
&& paramp
&& deserialize_func(*paramp, p, name_stack_range, new_name))
{
{
++mCurParam;
return true;
}
@ -2304,19 +2416,19 @@ namespace LLInitParam
{
return false;
}
}
}
else
{
return mValue.deserializeBlock(p, name_stack_range, new_name);
}
}
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const
{
const BaseBlock* base_block = diff_block
? &(diff_block->mValue)
: NULL;
mValue.serializeBlock(p, name_stack, base_block);
return mValue.serializeBlock(p, name_stack, predicate_rule, base_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
@ -2334,13 +2446,16 @@ namespace LLInitParam
return mValue.validateBlock(emit_errors);
}
bool isValid() const
{
return validateBlock(false);
}
static BlockDescriptor& getBlockDescriptor()
{
return value_t::getBlockDescriptor();
}
mutable bool mValidated; // lazy validation flag
private:
BlockDescriptor::all_params_list_t::iterator mCurParam;
@ -2358,16 +2473,14 @@ namespace LLInitParam
typedef T default_value_t;
ParamValue()
: T(),
mValidated(false)
: T()
{}
ParamValue(const default_value_t& value)
: T(value.getValue()),
mValidated(false)
: T(value.getValue())
{}
mutable bool mValidated; // lazy validation flag
bool isValid() const { return true; }
};
template<typename T, typename BLOCK_T>
@ -2380,18 +2493,15 @@ namespace LLInitParam
typedef LazyValue<T> default_value_t;
ParamValue()
: mValue(),
mValidated(false)
: mValue()
{}
ParamValue(const default_value_t& other)
: mValue(other),
mValidated(false)
: mValue(other)
{}
ParamValue(const T& value)
: mValue(value),
mValidated(false)
: mValue(value)
{}
void setValue(const value_t& val)
@ -2414,14 +2524,14 @@ namespace LLInitParam
return mValue.get().deserializeBlock(p, name_stack_range, new_name);
}
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const
bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const
{
if (mValue.empty()) return;
if (mValue.empty()) return false;
const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty())
? &(diff_block->mValue.get().getValue())
: NULL;
mValue.get().serializeBlock(p, name_stack, base_block);
return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_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
@ -2433,26 +2543,29 @@ namespace LLInitParam
{
return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite);
}
bool validateBlock(bool emit_errors = true) const
{
return mValue.empty() || mValue.get().validateBlock(emit_errors);
}
bool isValid() const
{
return validateBlock(false);
}
static BlockDescriptor& getBlockDescriptor()
{
return value_t::getBlockDescriptor();
}
mutable bool mValidated; // lazy validation flag
private:
LazyValue<T> mValue;
};
template<typename T, typename BLOCK_T>
class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T>
{
{
typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t;
public:
@ -2460,18 +2573,15 @@ namespace LLInitParam
typedef LazyValue<T> default_value_t;
ParamValue()
: mValue(),
mValidated(false)
: mValue()
{}
ParamValue(const default_value_t& other)
: mValue(other),
mValidated(false)
: mValue(other)
{}
ParamValue(const T& value)
: mValue(value),
mValidated(false)
: mValue(value)
{}
void setValue(const value_t& val)
@ -2489,7 +2599,10 @@ namespace LLInitParam
return mValue.get().getValue();
}
mutable bool mValidated; // lazy validation flag
bool isValid() const
{
return true;
}
private:
LazyValue<T> mValue;
@ -2504,12 +2617,10 @@ namespace LLInitParam
typedef LLSD default_value_t;
ParamValue()
: mValidated(false)
{}
ParamValue(const default_value_t& other)
: mValue(other),
mValidated(false)
: mValue(other)
{}
void setValue(const value_t& val) { mValue = val; }
@ -2519,16 +2630,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);
@ -2547,18 +2655,17 @@ namespace LLInitParam
BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative
} EValueAge;
typedef ParamValue<T> derived_t;
typedef CustomParamValue<T> self_t;
typedef Block<derived_t> block_t;
typedef TypeValues<T> derived_t;
typedef CustomParamValue<T> self_t;
typedef Block<ParamValue<T> > block_t;
typedef T default_value_t;
typedef T value_t;
typedef T value_t;
typedef void baseblock_base_class_t;
CustomParamValue(const default_value_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)
@ -2580,16 +2687,30 @@ 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);
//std::string key = typed_param.getValueName();
//// first try to write out name of name/value pair
//if (!key.empty())
//{
// if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key))
// {
// return parser.writeValue(key, name_stack);
// }
//}
// then try to serialize value directly
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
@ -2606,14 +2727,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 validateBlock(bool emit_errors = true) const
@ -2705,8 +2827,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,23 +27,25 @@
#include "linden_common.h"
// associated header
#include "llinstancetracker.h"
#include "llapr.h"
// STL headers
// std headers
// external library headers
// other Linden headers
//static
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
void LLInstanceTrackerBase::StaticBase::incrementDepth()
{
typedef std::map<std::string, void *> InstancesMap;
static InstancesMap instances;
// std::map::insert() is just what we want here. You attempt to insert a
// (key, value) pair. If the specified key doesn't yet exist, it inserts
// the pair and returns a std::pair of (iterator, true). If the specified
// key DOES exist, insert() simply returns (iterator, false). One lookup
// handles both cases.
return instances.insert(InstancesMap::value_type(info.name(),
InstancesMap::mapped_type()))
.first->second;
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

@ -46,22 +46,6 @@
class LL_COMMON_API LLInstanceTrackerBase
{
protected:
/// Get a process-unique void* pointer slot for the specified type_info
static void * & getInstances(std::type_info const & info);
/// Find or create a STATICDATA instance for the specified TRACKED class.
/// STATICDATA must be default-constructible.
template<typename STATICDATA, class TRACKED>
static STATICDATA& getStatic()
{
void *& instances = getInstances(typeid(TRACKED));
if (! instances)
{
instances = new STATICDATA;
}
return *static_cast<STATICDATA*>(instances);
}
/// It's not essential to derive your STATICDATA (for use with
/// getStatic()) from StaticBase; it's just that both known
/// implementations do.
@ -70,15 +54,21 @@ 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
/// @NOTE: this class is not thread-safe unless used as read-only
template<typename T, typename KEY = void>
class LLInstanceTracker : public LLInstanceTrackerBase
{
typedef LLInstanceTracker<T, KEY> MyT;
@ -87,7 +77,7 @@ class LLInstanceTracker : public LLInstanceTrackerBase
{
InstanceMap sMap;
};
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
static StaticData& getStatic() { static StaticData sData; return sData;}
static InstanceMap& getMap_() { return getStatic().sMap; }
public:
@ -99,12 +89,12 @@ public:
instance_iter(const typename InstanceMap::iterator& it)
: mIterator(it)
{
++getStatic().sIterationNestDepth;
getStatic().incrementDepth();
}
~instance_iter()
{
--getStatic().sIterationNestDepth;
getStatic().decrementDepth();
}
@ -131,20 +121,20 @@ public:
typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
key_iter(typename InstanceMap::iterator it)
: mIterator(it)
: mIterator(it)
{
++getStatic().sIterationNestDepth;
getStatic().incrementDepth();
}
key_iter(const key_iter& other)
: mIterator(other.mIterator)
: mIterator(other.mIterator)
{
++getStatic().sIterationNestDepth;
getStatic().incrementDepth();
}
~key_iter()
{
--getStatic().sIterationNestDepth;
getStatic().decrementDepth();
}
@ -182,7 +172,10 @@ public:
return instance_iter(getMap_().end());
}
static S32 instanceCount() { return getMap_().size(); }
static S32 instanceCount()
{
return getMap_().size();
}
static key_iter beginKeys()
{
@ -203,7 +196,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); }
@ -227,18 +220,18 @@ 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
{
InstanceSet sSet;
};
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
static StaticData& getStatic() { static StaticData sData; return sData; }
static InstanceSet& getSet_() { return getStatic().sSet; }
public:
@ -265,18 +258,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:
@ -309,7 +302,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

@ -1,40 +0,0 @@
/**
* @file lllazy.cpp
* @author Nat Goodspeed
* @date 2009-01-28
* @brief Implementation for lllazy.
*
* $LicenseInfo:firstyear=2009&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$
*/
// Precompiled header
#include "linden_common.h"
// associated header
#include "lllazy.h"
// STL headers
// std headers
// external library headers
// other Linden headers
// lllazy.h is presently header-only. This file exists only because our CMake
// test macro ADD_BUILD_TEST requires it.
int dummy = 0;

View File

@ -1,399 +0,0 @@
/**
* @file lllazy.h
* @author Nat Goodspeed
* @date 2009-01-22
* @brief Lazy instantiation of specified type. Useful in conjunction with
* Michael Feathers's "Extract and Override Getter" ("Working
* Effectively with Legacy Code", p. 352).
*
* Quoting his synopsis of steps on p.355:
*
* 1. Identify the object you need a getter for.
* 2. Extract all of the logic needed to create the object into a getter.
* 3. Replace all uses of the object with calls to the getter, and initialize
* the reference that holds the object to null in all constructors.
* 4. Add the first-time logic to the getter so that the object is constructed
* and assigned to the reference whenever the reference is null.
* 5. Subclass the class and override the getter to provide an alternative
* object for testing.
*
* It's the second half of bullet 3 (3b, as it were) that bothers me. I find
* it all too easy to imagine adding pointer initializers to all but one
* constructor... the one not exercised by my tests. That suggested using
* (e.g.) boost::scoped_ptr<MyObject> so you don't have to worry about
* destroying it either.
*
* However, introducing additional machinery allows us to encapsulate bullet 4
* as well.
*
* $LicenseInfo:firstyear=2009&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$
*/
#if ! defined(LL_LLLAZY_H)
#define LL_LLLAZY_H
#include <boost/function.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/lambda/construct.hpp>
#include <stdexcept>
/// LLLazyCommon simply factors out of LLLazy<T> things that don't depend on
/// its template parameter.
class LLLazyCommon
{
public:
/**
* This exception is thrown if you try to replace an LLLazy<T>'s factory
* (or T* instance) after it already has an instance in hand. Since T
* might well be stateful, we can't know the effect of silently discarding
* and replacing an existing instance, so we disallow it. This facility is
* intended for testing, and in a test scenario we can definitely control
* that.
*/
struct InstanceChange: public std::runtime_error
{
InstanceChange(const std::string& what): std::runtime_error(what) {}
};
protected:
/**
* InstanceChange might be appropriate in a couple of different LLLazy<T>
* methods. Factor out the common logic.
*/
template <typename PTR>
static void ensureNoInstance(const PTR& ptr)
{
if (ptr)
{
// Too late: we've already instantiated the lazy object. We don't
// know whether it's stateful or not, so it's not safe to discard
// the existing instance in favor of a replacement.
throw InstanceChange("Too late to replace LLLazy instance");
}
}
};
/**
* LLLazy<T> is useful when you have an outer class Outer that you're trying
* to bring under unit test, that contains a data member difficult to
* instantiate in a test harness. Typically the data member's class Inner has
* many thorny dependencies. Feathers generally advocates "Extract and
* Override Factory Method" (p. 350). But in C++, you can't call a derived
* class override of a virtual method from the derived class constructor,
* which limits applicability of "Extract and Override Factory Method." For
* such cases Feathers presents "Extract and Override Getter" (p. 352).
*
* So we'll assume that your class Outer contains a member like this:
* @code
* Inner mInner;
* @endcode
*
* LLLazy<Inner> can be used to replace this member. You can directly declare:
* @code
* LLLazy<Inner> mInner;
* @endcode
* and change references to mInner accordingly.
*
* (Alternatively, you can add a base class of the form
* <tt>LLLazyBase<Inner></tt>. This is discussed further in the LLLazyBase<T>
* documentation.)
*
* LLLazy<T> binds a <tt>boost::scoped_ptr<T></tt> and a factory functor
* returning T*. You can either bind that functor explicitly or let it default
* to the expression <tt>new T()</tt>.
*
* As long as LLLazy<T> remains unreferenced, its T remains uninstantiated.
* The first time you use get(), <tt>operator*()</tt> or <tt>operator->()</tt>
* it will instantiate its T and thereafter behave like a pointer to it.
*
* Thus, any existing reference to <tt>mInner.member</tt> should be replaced
* with <tt>mInner->member</tt>. Any simple reference to @c mInner should be
* replaced by <tt>*mInner</tt>.
*
* (If the original declaration was a pointer initialized in Outer's
* constructor, e.g. <tt>Inner* mInner</tt>, so much the better. In that case
* you should be able to drop in <tt>LLLazy<Inner></tt> without much change.)
*
* The support for "Extract and Override Getter" lies in the fact that you can
* replace the factory functor -- or provide an explicit T*. Presumably this
* is most useful from a test subclass -- which suggests that your @c mInner
* member should be @c protected.
*
* Note that <tt>boost::lambda::new_ptr<T>()</tt> makes a dandy factory
* functor, for either the set() method or LLLazy<T>'s constructor. If your T
* requires constructor arguments, use an expression more like
* <tt>boost::lambda::bind(boost::lambda::new_ptr<T>(), arg1, arg2, ...)</tt>.
*
* Of course the point of replacing the functor is to substitute a class that,
* though referenced as Inner*, is not an Inner; presumably this is a testing
* subclass of Inner (e.g. TestInner). Thus your test subclass TestOuter for
* the containing class Outer will contain something like this:
* @code
* class TestOuter: public Outer
* {
* public:
* TestOuter()
* {
* // mInner must be 'protected' rather than 'private'
* mInner.set(boost::lambda::new_ptr<TestInner>());
* }
* ...
* };
* @endcode
*/
template <typename T>
class LLLazy: public LLLazyCommon
{
public:
/// Any nullary functor returning T* will work as a Factory
typedef boost::function<T* ()> Factory;
/// The default LLLazy constructor uses <tt>new T()</tt> as its Factory
LLLazy():
mFactory(boost::lambda::new_ptr<T>())
{}
/// Bind an explicit Factory functor
LLLazy(const Factory& factory):
mFactory(factory)
{}
/// Reference T, instantiating it if this is the first access
const T& get() const
{
if (! mInstance)
{
// use the bound Factory functor
mInstance.reset(mFactory());
}
return *mInstance;
}
/// non-const get()
T& get()
{
return const_cast<T&>(const_cast<const LLLazy<T>*>(this)->get());
}
/// operator*() is equivalent to get()
const T& operator*() const { return get(); }
/// operator*() is equivalent to get()
T& operator*() { return get(); }
/**
* operator->() must return (something resembling) T*. It's tempting to
* return the underlying boost::scoped_ptr<T>, but that would require
* breaking out the lazy-instantiation logic from get() into a common
* private method. Assume the pointer used for operator->() access is very
* short-lived.
*/
const T* operator->() const { return &get(); }
/// non-const operator->()
T* operator->() { return &get(); }
/// set(Factory). This will throw InstanceChange if mInstance has already
/// been set.
void set(const Factory& factory)
{
ensureNoInstance(mInstance);
mFactory = factory;
}
/// set(T*). This will throw InstanceChange if mInstance has already been
/// set.
void set(T* instance)
{
ensureNoInstance(mInstance);
mInstance.reset(instance);
}
private:
Factory mFactory;
// Consider an LLLazy<T> member of a class we're accessing by const
// reference. We want to allow even const methods to touch the LLLazy<T>
// member. Hence the actual pointer must be mutable because such access
// might assign it.
mutable boost::scoped_ptr<T> mInstance;
};
#if (! defined(__GNUC__)) || (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
// Not gcc at all, or a gcc more recent than gcc 3.3
#define GCC33 0
#else
#define GCC33 1
#endif
/**
* LLLazyBase<T> wraps LLLazy<T>, giving you an alternative way to replace
* <tt>Inner mInner;</tt>. Instead of coding <tt>LLLazy<Inner> mInner</tt>,
* you can add LLLazyBase<Inner> to your Outer class's bases, e.g.:
* @code
* class Outer: public LLLazyBase<Inner>
* {
* ...
* };
* @endcode
*
* This gives you @c public get() and @c protected set() methods without
* having to make your LLLazy<Inner> member @c protected. The tradeoff is that
* you must access the wrapped LLLazy<Inner> using get() and set() rather than
* with <tt>operator*()</tt> or <tt>operator->()</tt>.
*
* This mechanism can be used for more than one member, but only if they're of
* different types. That is, you can replace:
* @code
* DifficultClass mDifficult;
* AwkwardType mAwkward;
* @endcode
* with:
* @code
* class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType>
* {
* ...
* };
* @endcode
* but for a situation like this:
* @code
* DifficultClass mMainDifficult, mAuxDifficult;
* @endcode
* you should directly embed LLLazy<DifficultClass> (q.v.).
*
* For multiple LLLazyBase bases, e.g. the <tt>LLLazyBase<DifficultClass>,
* LLLazyBase<AwkwardType></tt> example above, access the relevant get()/set()
* as (e.g.) <tt>LLLazyBase<DifficultClass>::get()</tt>. (This is why you
* can't have multiple LLLazyBase<T> of the same T.) For a bit of syntactic
* sugar, please see getLazy()/setLazy().
*/
template <typename T>
class LLLazyBase
{
public:
/// invoke default LLLazy constructor
LLLazyBase() {}
/// make wrapped LLLazy bind an explicit Factory
LLLazyBase(const typename LLLazy<T>::Factory& factory):
mInstance(factory)
{}
/// access to LLLazy::get()
T& get() { return *mInstance; }
/// access to LLLazy::get()
const T& get() const { return *mInstance; }
protected:
// see getLazy()/setLazy()
#if (! GCC33)
template <typename T2, class MYCLASS> friend T2& getLazy(MYCLASS* this_);
template <typename T2, class MYCLASS> friend const T2& getLazy(const MYCLASS* this_);
#else // gcc 3.3
template <typename T2, class MYCLASS> friend T2& getLazy(const MYCLASS* this_);
#endif // gcc 3.3
template <typename T2, class MYCLASS> friend void setLazy(MYCLASS* this_, T2* instance);
template <typename T2, class MYCLASS>
friend void setLazy(MYCLASS* this_, const typename LLLazy<T2>::Factory& factory);
/// access to LLLazy::set(Factory)
void set(const typename LLLazy<T>::Factory& factory)
{
mInstance.set(factory);
}
/// access to LLLazy::set(T*)
void set(T* instance)
{
mInstance.set(instance);
}
private:
LLLazy<T> mInstance;
};
/**
* @name getLazy()/setLazy()
* Suppose you have something like the following:
* @code
* class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType>
* {
* ...
* };
* @endcode
*
* Your methods can reference the @c DifficultClass instance using
* <tt>LLLazyBase<DifficultClass>::get()</tt>, which is admittedly a bit ugly.
* Alternatively, you can write <tt>getLazy<DifficultClass>(this)</tt>, which
* is somewhat more straightforward to read.
*
* Similarly,
* @code
* LLLazyBase<DifficultClass>::set(new TestDifficultClass());
* @endcode
* could instead be written:
* @code
* setLazy<DifficultClass>(this, new TestDifficultClass());
* @endcode
*
* @note
* I wanted to provide getLazy() and setLazy() without explicitly passing @c
* this. That would imply making them methods on a base class rather than free
* functions. But if <tt>LLLazyBase<T></tt> derives normally from (say) @c
* LLLazyGrandBase providing those methods, then unqualified getLazy() would
* be ambiguous: you'd have to write <tt>LLLazyBase<T>::getLazy<T>()</tt>,
* which is even uglier than <tt>LLLazyBase<T>::get()</tt>, and therefore
* pointless. You can make the compiler not care which @c LLLazyGrandBase
* instance you're talking about by making @c LLLazyGrandBase a @c virtual
* base class of @c LLLazyBase. But in that case,
* <tt>LLLazyGrandBase::getLazy<T>()</tt> can't access
* <tt>LLLazyBase<T>::get()</tt>!
*
* We want <tt>getLazy<T>()</tt> to access <tt>LLLazyBase<T>::get()</tt> as if
* in the lexical context of some subclass method. Ironically, free functions
* let us do that better than methods on a @c virtual base class -- but that
* implies passing @c this explicitly. So be it.
*/
//@{
#if (! GCC33)
template <typename T, class MYCLASS>
T& getLazy(MYCLASS* this_) { return this_->LLLazyBase<T>::get(); }
template <typename T, class MYCLASS>
const T& getLazy(const MYCLASS* this_) { return this_->LLLazyBase<T>::get(); }
#else // gcc 3.3
// For const-correctness, we really should have two getLazy() variants: one
// accepting const MYCLASS* and returning const T&, the other accepting
// non-const MYCLASS* and returning non-const T&. This works fine on the Mac
// (gcc 4.0.1) and Windows (MSVC 8.0), but fails on our Linux 32-bit Debian
// Sarge stations (gcc 3.3.5). Since I really don't know how to beat that aging
// compiler over the head to make it do the right thing, I'm going to have to
// move forward with the wrong thing: a single getLazy() function that accepts
// const MYCLASS* and returns non-const T&.
template <typename T, class MYCLASS>
T& getLazy(const MYCLASS* this_) { return const_cast<MYCLASS*>(this_)->LLLazyBase<T>::get(); }
#endif // gcc 3.3
template <typename T, class MYCLASS>
void setLazy(MYCLASS* this_, T* instance) { this_->LLLazyBase<T>::set(instance); }
template <typename T, class MYCLASS>
void setLazy(MYCLASS* this_, const typename LLLazy<T>::Factory& factory)
{
this_->LLLazyBase<T>::set(factory);
}
//@}
#endif /* ! defined(LL_LLLAZY_H) */

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

@ -1,895 +0,0 @@
/**
* @file lllocalidhashmap.h
* @brief Map specialized for dealing with local ids
*
* $LicenseInfo:firstyear=2003&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_LLLOCALIDHASHMAP_H
#define LL_LLLOCALIDHASHMAP_H
#include "stdtypes.h"
#include "llerror.h"
const S32 MAX_ITERS = 4;
// LocalID hash map
//
// LLLocalIDHashNode
//
template <class DATA, int SIZE>
class LLLocalIDHashNode
{
public:
LLLocalIDHashNode();
public:
S32 mCount;
U32 mKey[SIZE];
DATA mData[SIZE];
LLLocalIDHashNode<DATA, SIZE> *mNextNodep;
};
//
// LLLocalIDHashNode implementation
//
template <class DATA, int SIZE>
LLLocalIDHashNode<DATA, SIZE>::LLLocalIDHashNode()
{
mCount = 0;
mNextNodep = NULL;
}
//
// LLLocalIDHashMapIter
//
template <class DATA_TYPE, int SIZE>
class LLLocalIDHashMap;
template <class DATA_TYPE, int SIZE>
class LLLocalIDHashMapIter
{
public:
LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
~LLLocalIDHashMapIter();
void setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp);
inline void first();
inline void next();
inline DATA_TYPE& current(); // *NOTE: Deprecate? Phoenix 2005-04-15
inline BOOL done() const;
inline S32 currentBin() const;
inline void setBin(S32 bin);
DATA_TYPE& operator*() const
{
return mCurHashNodep->mData[mCurHashNodeKey];
}
DATA_TYPE* operator->() const
{
return &(operator*());
}
LLLocalIDHashMap<DATA_TYPE, SIZE> *mHashMapp;
LLLocalIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep;
S32 mCurHashMapNodeNum;
S32 mCurHashNodeKey;
DATA_TYPE mNull;
S32 mIterID;
};
template <class DATA_TYPE, int SIZE>
class LLLocalIDHashMap
{
public:
friend class LLLocalIDHashMapIter<DATA_TYPE, SIZE>;
LLLocalIDHashMap(); // DO NOT use this unless you explicitly setNull, or the data type constructs a "null"
// object by default
// basic constructor including sorter
LLLocalIDHashMap(const DATA_TYPE &null_data);
// Hack, this should really be a const ref, but I'm not doing it that way because the sim
// usually uses pointers.
~LLLocalIDHashMap();
inline DATA_TYPE &get(const U32 local_id);
inline BOOL check(const U32 local_id) const;
inline DATA_TYPE &set(const U32 local_id, const DATA_TYPE data);
inline BOOL remove(const U32 local_id);
void removeAll();
void setNull(const DATA_TYPE data) { mNull = data; }
inline S32 getLength() const; // Warning, NOT O(1!)
void dumpIter();
void dumpBin(U32 bin);
protected:
// Only used by the iterator.
void addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter);
void removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter);
// Remove the item and shift all items afterward down the list,
// fixing up iterators as we go.
BOOL removeWithShift(const U32 local_id);
protected:
LLLocalIDHashNode<DATA_TYPE, SIZE> mNodes[256];
S32 mIterCount;
LLLocalIDHashMapIter<DATA_TYPE, SIZE> *mIters[MAX_ITERS];
DATA_TYPE mNull;
};
//
// LLLocalIDHashMap implementation
//
template <class DATA_TYPE, int SIZE>
LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap()
: mIterCount(0),
mNull()
{
S32 i;
for (i = 0; i < MAX_ITERS; i++)
{
mIters[i] = NULL;
}
}
template <class DATA_TYPE, int SIZE>
LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap(const DATA_TYPE &null_data)
: mIterCount(0),
mNull(null_data)
{
S32 i;
for (i = 0; i < MAX_ITERS; i++)
{
mIters[i] = NULL;
}
}
template <class DATA_TYPE, int SIZE>
LLLocalIDHashMap<DATA_TYPE, SIZE>::~LLLocalIDHashMap()
{
S32 i;
for (i = 0; i < MAX_ITERS; i++)
{
if (mIters[i])
{
mIters[i]->mHashMapp = NULL;
mIterCount--;
}
}
removeAll();
}
template <class DATA_TYPE, int SIZE>
void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeAll()
{
S32 bin;
for (bin = 0; bin < 256; bin++)
{
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
BOOL first = TRUE;
do // First node guaranteed to be there
{
S32 i;
const S32 count = nodep->mCount;
// Iterate through all members of this node
for (i = 0; i < count; i++)
{
nodep->mData[i] = mNull;
}
nodep->mCount = 0;
// Done with all objects in this node, go to the next.
LLLocalIDHashNode<DATA_TYPE, SIZE>* curp = nodep;
nodep = nodep->mNextNodep;
// Delete the node if it's not the first node
if (first)
{
first = FALSE;
curp->mNextNodep = NULL;
}
else
{
delete curp;
}
} while (nodep);
}
}
template <class DATA_TYPE, int SIZE>
void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpIter()
{
std::cout << "Hash map with " << mIterCount << " iterators" << std::endl;
std::cout << "Hash Map Iterators:" << std::endl;
S32 i;
for (i = 0; i < MAX_ITERS; i++)
{
if (mIters[i])
{
llinfos << i << " " << mIters[i]->mCurHashNodep << " " << mIters[i]->mCurHashNodeKey << llendl;
}
else
{
llinfos << i << "null" << llendl;
}
}
}
template <class DATA_TYPE, int SIZE>
void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpBin(U32 bin)
{
std::cout << "Dump bin " << bin << std::endl;
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
S32 node = 0;
do // First node guaranteed to be there.
{
std::cout << "Bin " << bin
<< " node " << node
<< " count " << nodep->mCount
<< " contains " << std::flush;
S32 i;
for (i = 0; i < nodep->mCount; i++)
{
std::cout << nodep->mData[i] << " " << std::flush;
}
std::cout << std::endl;
nodep = nodep->mNextNodep;
node++;
} while (nodep);
}
template <class DATA_TYPE, int SIZE>
inline S32 LLLocalIDHashMap<DATA_TYPE, SIZE>::getLength() const
{
S32 count = 0;
S32 bin;
for (bin = 0; bin < 256; bin++)
{
const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin];
while (nodep)
{
count += nodep->mCount;
nodep = nodep->mNextNodep;
}
}
return count;
}
template <class DATA_TYPE, int SIZE>
inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::get(const U32 local_id)
{
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
do // First node guaranteed to be there
{
S32 i;
const S32 count = nodep->mCount;
// Iterate through all members of this node
for (i = 0; i < count; i++)
{
if (nodep->mKey[i] == local_id)
{
// We found it.
return nodep->mData[i];
}
}
// Done with all objects in this node, go to the next.
nodep = nodep->mNextNodep;
} while (nodep);
return mNull;
}
template <class DATA_TYPE, int SIZE>
inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::check(const U32 local_id) const
{
const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
do // First node guaranteed to be there
{
S32 i;
const S32 count = nodep->mCount;
// Iterate through all members of this node
for (i = 0; i < count; i++)
{
if (nodep->mKey[i] == local_id)
{
// We found it.
return TRUE;
}
}
// Done with all objects in this node, go to the next.
nodep = nodep->mNextNodep;
} while (nodep);
// Didn't find anything
return FALSE;
}
template <class DATA_TYPE, int SIZE>
inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::set(const U32 local_id, const DATA_TYPE data)
{
// Set is just like a normal find, except that if we find a match
// we replace it with the input value.
// If we don't find a match, we append to the end of the list.
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff];
while (1)
{
const S32 count = nodep->mCount;
S32 i;
for (i = 0; i < count; i++)
{
if (nodep->mKey[i] == local_id)
{
// We found a match for this key, replace the data with
// the incoming data.
nodep->mData[i] = data;
return nodep->mData[i];
}
}
if (!nodep->mNextNodep)
{
// We've iterated through all of the keys without finding a match
if (i < SIZE)
{
// There's still some space on this node, append
// the key and data to it.
nodep->mKey[i] = local_id;
nodep->mData[i] = data;
nodep->mCount++;
return nodep->mData[i];
}
else
{
// This node is full, append a new node to the end.
nodep->mNextNodep = new LLLocalIDHashNode<DATA_TYPE, SIZE>;
nodep->mNextNodep->mKey[0] = local_id;
nodep->mNextNodep->mData[0] = data;
nodep->mNextNodep->mCount = 1;
return nodep->mNextNodep->mData[0];
}
}
// No match on this node, go to the next
nodep = nodep->mNextNodep;
}
}
template <class DATA_TYPE, int SIZE>
inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::remove(const U32 local_id)
{
// Remove is the trickiest operation.
// What we want to do is swap the last element of the last
// node if we find the one that we want to remove, but we have
// to deal with deleting the node from the tail if it's empty, but
// NOT if it's the only node left.
const S32 node_index = local_id & 0xff;
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index];
// A modification of the standard search algorithm.
do // First node guaranteed to be there
{
const S32 count = nodep->mCount;
S32 i;
for (i = 0; i < count; i++)
{
if (nodep->mKey[i] == local_id)
{
// If we're removing the item currently pointed to by one
// or more iterators, we can just swap in the last item
// and back the iterator(s) up by one.
// Otherwise, we need to do a slow and safe shift of all
// items back to one position to fill the hole and fix up
// all iterators we find.
BOOL need_shift = FALSE;
S32 cur_iter;
if (mIterCount)
{
for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++)
{
if (mIters[cur_iter])
{
// We only care if the hash map node is on the one
// that we're working on. If it's before, we've already
// traversed it, if it's after, changing the order doesn't
// matter.
if (mIters[cur_iter]->mCurHashMapNodeNum == node_index)
{
if ((mIters[cur_iter]->mCurHashNodep == nodep)
&& (mIters[cur_iter]->mCurHashNodeKey == i))
{
// it's on the one we're deleting, we'll
// fix the iterator quickly below.
}
else
{
// We're trying to remove an item on this
// iterator's chain that this
// iterator doesn't point to! We need to do
// the slow remove-and-shift-down case.
need_shift = TRUE;
}
}
}
}
}
// Removing an item that isn't pointed to by all iterators
if (need_shift)
{
return removeWithShift(local_id);
}
// Fix the iterators that point to this node/i pair, the
// one we're deleting
for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++)
{
if (mIters[cur_iter])
{
// We only care if the hash map node is on the one
// that we're working on. If it's before, we've already
// traversed it, if it's after, changing the order doesn't
// matter.
if (mIters[cur_iter]->mCurHashMapNodeNum == node_index)
{
if ((mIters[cur_iter]->mCurHashNodep == nodep)
&& (mIters[cur_iter]->mCurHashNodeKey == i))
{
// We can handle the case where we're deleting
// the element we're on trivially (sort of).
if (nodep->mCount > 1)
{
// If we're not going to delete this node,
// it's OK.
mIters[cur_iter]->mCurHashNodeKey--;
}
else
{
// We're going to delete this node, because this
// is the last element on it.
// Find the next node, and then back up one.
mIters[cur_iter]->next();
mIters[cur_iter]->mCurHashNodeKey--;
}
}
}
}
}
// We found the node that we want to remove.
// Find the last (and next-to-last) node, and the index of the last
// element. We could conceviably start from the node we're on,
// but that makes it more complicated, this is easier.
LLLocalIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[node_index];
LLLocalIDHashNode<DATA_TYPE, SIZE> *lastp = prevp;
// Find the last and next-to-last
while (lastp->mNextNodep)
{
prevp = lastp;
lastp = lastp->mNextNodep;
}
// First, swap in the last to the current location.
nodep->mKey[i] = lastp->mKey[lastp->mCount - 1];
nodep->mData[i] = lastp->mData[lastp->mCount - 1];
// Now, we delete the entry
lastp->mCount--;
lastp->mData[lastp->mCount] = mNull;
if (!lastp->mCount)
{
// We deleted the last element!
if (lastp != &mNodes[local_id & 0xff])
{
// Only blitz the node if it's not the head
// Set the previous node to point to NULL, then
// blitz the empty last node
prevp->mNextNodep = NULL;
delete lastp;
}
}
return TRUE;
}
}
// Iterate to the next node, we've scanned all the entries in this one.
nodep = nodep->mNextNodep;
} while (nodep);
return FALSE;
}
template <class DATA_TYPE, int SIZE>
BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::removeWithShift(const U32 local_id)
{
const S32 node_index = local_id & 0xFF;
LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index];
LLLocalIDHashNode<DATA_TYPE, SIZE>* prevp = NULL;
BOOL found = FALSE;
do // First node guaranteed to be there
{
const S32 count = nodep->mCount;
S32 i;
for (i = 0; i < count; i++)
{
if (nodep->mKey[i] == local_id)
{
// Found the item. Start shifting items from later
// in the list over this item.
found = TRUE;
}
if (found)
{
// If there is an iterator on this node, we need to
// back it up.
S32 cur_iter;
for (cur_iter = 0; cur_iter <MAX_ITERS; cur_iter++)
{
LLLocalIDHashMapIter<DATA_TYPE, SIZE>* iter;
iter = mIters[cur_iter];
// If an iterator is on this node,i pair, then back it up.
if (iter
&& iter->mCurHashMapNodeNum == node_index
&& iter->mCurHashNodep == nodep
&& iter->mCurHashNodeKey == i)
{
if (i > 0)
{
// Don't need to move iterator nodep, since
// we're in the same node.
iter->mCurHashNodeKey--;
}
else if (prevp)
{
// need to go the previous node, last item
iter->mCurHashNodep = prevp;
iter->mCurHashNodeKey = prevp->mCount - 1;
}
else
{
// we're on the first item in the list, but
// need to go back anyhow.
// BUG: If this deletion empties the list,
// iter->done() will be wrong until
// iter->next() is called.
iter->mCurHashNodeKey = -1;
}
}
}
// Copy data from the next position into this position.
if (i < count-1)
{
// we're not on the last item in the node,
// so we can copy within the node
nodep->mKey[i] = nodep->mKey[i+1];
nodep->mData[i] = nodep->mData[i+1];
}
else if (nodep->mNextNodep)
{
// we're on the last item in the node,
// but there's a next node we can copy from
nodep->mKey[i] = nodep->mNextNodep->mKey[0];
nodep->mData[i] = nodep->mNextNodep->mData[0];
}
else
{
// We're on the last position in the list.
// No one to copy from. Replace with nothing.
nodep->mKey[i] = 0;
nodep->mData[i] = mNull;
}
}
}
// Last node in chain, so delete the last node
if (found
&& !nodep->mNextNodep)
{
// delete the last item off the last node
nodep->mCount--;
if (nodep->mCount == 0)
{
// We deleted the last element!
if (nodep != &mNodes[node_index])
{
// Always have a prevp if we're not the head.
llassert(prevp);
// Only blitz the node if it's not the head
// Set the previous node to point to NULL, then
// blitz the empty last node
prevp->mNextNodep = NULL;
delete nodep;
nodep = NULL;
}
}
// Deleted last item in chain, so we're done.
return found;
}
prevp = nodep;
nodep = nodep->mNextNodep;
} while (nodep);
return found;
}
template <class DATA_TYPE, int SIZE>
void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter)
{
S32 i;
for (i = 0; i < MAX_ITERS; i++)
{
if (mIters[i] == iter)
{
mIters[i] = NULL;
mIterCount--;
return;
}
}
llerrs << "Iterator " << iter << " not found for removal in hash map!" << llendl;
}
template <class DATA_TYPE, int SIZE>
void LLLocalIDHashMap<DATA_TYPE, SIZE>::addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter)
{
S32 i;
for (i = 0; i < MAX_ITERS; i++)
{
if (mIters[i] == NULL)
{
mIters[i] = iter;
mIterCount++;
return;
}
}
llerrs << "More than " << MAX_ITERS << " iterating over a map simultaneously!" << llendl;
}
//
// LLLocalIDHashMapIter Implementation
//
template <class DATA_TYPE, int SIZE>
LLLocalIDHashMapIter<DATA_TYPE, SIZE>::LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
{
mHashMapp = NULL;
setMap(hash_mapp);
}
template <class DATA_TYPE, int SIZE>
LLLocalIDHashMapIter<DATA_TYPE, SIZE>::~LLLocalIDHashMapIter()
{
if (mHashMapp)
{
mHashMapp->removeIter(this);
}
}
template <class DATA_TYPE, int SIZE>
void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp)
{
if (mHashMapp)
{
mHashMapp->removeIter(this);
}
mHashMapp = hash_mapp;
if (mHashMapp)
{
mHashMapp->addIter(this);
}
mCurHashNodep = NULL;
mCurHashMapNodeNum = -1;
mCurHashNodeKey = 0;
}
template <class DATA_TYPE, int SIZE>
inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::first()
{
// Iterate through until we find the first non-empty node;
S32 i;
for (i = 0; i < 256; i++)
{
if (mHashMapp->mNodes[i].mCount)
{
mCurHashNodep = &mHashMapp->mNodes[i];
mCurHashMapNodeNum = i;
mCurHashNodeKey = 0;
//return mCurHashNodep->mData[0];
return;
}
}
// Completely empty!
mCurHashNodep = NULL;
//return mNull;
return;
}
template <class DATA_TYPE, int SIZE>
inline BOOL LLLocalIDHashMapIter<DATA_TYPE, SIZE>::done() const
{
return mCurHashNodep ? FALSE : TRUE;
}
template <class DATA_TYPE, int SIZE>
inline S32 LLLocalIDHashMapIter<DATA_TYPE, SIZE>::currentBin() const
{
if ( (mCurHashMapNodeNum > 255)
||(mCurHashMapNodeNum < 0))
{
return 0;
}
else
{
return mCurHashMapNodeNum;
}
}
template <class DATA_TYPE, int SIZE>
inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setBin(S32 bin)
{
// Iterate through until we find the first non-empty node;
S32 i;
bin = llclamp(bin, 0, 255);
for (i = bin; i < 256; i++)
{
if (mHashMapp->mNodes[i].mCount)
{
mCurHashNodep = &mHashMapp->mNodes[i];
mCurHashMapNodeNum = i;
mCurHashNodeKey = 0;
return;
}
}
for (i = 0; i < bin; i++)
{
if (mHashMapp->mNodes[i].mCount)
{
mCurHashNodep = &mHashMapp->mNodes[i];
mCurHashMapNodeNum = i;
mCurHashNodeKey = 0;
return;
}
}
// Completely empty!
mCurHashNodep = NULL;
}
template <class DATA_TYPE, int SIZE>
inline DATA_TYPE &LLLocalIDHashMapIter<DATA_TYPE, SIZE>::current()
{
if (!mCurHashNodep)
{
return mNull;
}
return mCurHashNodep->mData[mCurHashNodeKey];
}
template <class DATA_TYPE, int SIZE>
inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::next()
{
// No current entry, this iterator is done
if (!mCurHashNodep)
{
//return mNull;
return;
}
// Go to the next element
mCurHashNodeKey++;
if (mCurHashNodeKey < mCurHashNodep->mCount)
{
// We're not done with this node, return the current element
//return mCurHashNodep->mData[mCurHashNodeKey];
return;
}
// Done with this node, move to the next
mCurHashNodep = mCurHashNodep->mNextNodep;
if (mCurHashNodep)
{
// Return the first element
mCurHashNodeKey = 0;
//return mCurHashNodep->mData[0];
return;
}
// Find the next non-empty node (keyed on the first byte)
mCurHashMapNodeNum++;
S32 i;
for (i = mCurHashMapNodeNum; i < 256; i++)
{
if (mHashMapp->mNodes[i].mCount)
{
// We found one that wasn't empty
mCurHashNodep = &mHashMapp->mNodes[i];
mCurHashMapNodeNum = i;
mCurHashNodeKey = 0;
//return mCurHashNodep->mData[0];
return;
}
}
// OK, we're done, nothing else to iterate
mCurHashNodep = NULL;
mHashMapp->mIterCount--; // Decrement since we're safe to do removes now
//return mNull;
return;
}
#endif // LL_LLLOCALIDHASHMAP_H

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,40 @@ protected:
Type* mPointer;
};
template<typename Type>
class LLCopyOnWritePointer : public LLPointer<Type>
{
public:
typedef LLCopyOnWritePointer<Type> self_t;
typedef LLPointer<Type> pointer_t;
LLCopyOnWritePointer()
{}
LLCopyOnWritePointer(Type* ptr)
: LLPointer<Type>(ptr)
{}
LLCopyOnWritePointer(LLPointer<Type>& ptr)
: LLPointer<Type>(ptr)
{}
Type* write()
{
makeUnique();
return pointer_t::mPointer;
}
void makeUnique()
{
if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1)
{
*(pointer_t* )(this) = new Type(*pointer_t::mPointer);
}
}
const Type* operator->() const { return pointer_t::mPointer; }
const Type& operator*() const { return *pointer_t::mPointer; }
};
#endif

View File

@ -1,7 +1,6 @@
/**
* @file llfunctorregistry.cpp
* @author Kent Quirk
* @brief Maintains a registry of named callback functors taking a single LLSD parameter
/**
* @file llpredicate.cpp
* @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
@ -23,11 +22,20 @@
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
**/
*/
#include "linden_common.h"
#include "llfunctorregistry.h"
// This is a default functor always resident in the system.
// It's used whenever a functor isn't found in the registry, so that
// we at least log the data relating to the user response.
#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

@ -29,6 +29,7 @@
#include "llinitparam.h"
#include "llsdparam.h"
#include "llwin32headerslean.h"
#include "apr_thread_proc.h"
#include <boost/shared_ptr.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
@ -38,8 +39,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<F64, LLUnits::Megahertz> LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }
bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); }
bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }

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<F64, LLUnits::Megahertz> getCPUFrequency() const;
bool hasSSE() const;
bool hasSSE2() const;
bool hasAltivec() const;

View File

@ -1,724 +0,0 @@
/**
* @file llptrskiplist.h
* @brief Skip list implementation.
*
* $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_LLPTRSKIPLIST_H
#define LL_LLPTRSKIPLIST_H
#include "llerror.h"
#include "llrand.h"
//#include "vmath.h"
#include "llrand.h"
/////////////////////////////////////////////
//
// LLPtrSkipList implementation - skip list for pointers to objects
//
template <class DATA_TYPE, S32 BINARY_DEPTH = 8>
class LLPtrSkipList
{
public:
friend class LLPtrSkipNode;
// basic constructor
LLPtrSkipList();
// basic constructor including sorter
LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second),
BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second));
~LLPtrSkipList();
inline void setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second));
inline void setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second));
inline BOOL addData(DATA_TYPE *data);
inline BOOL checkData(const DATA_TYPE *data);
inline S32 getLength(); // returns number of items in the list - NOT constant time!
inline BOOL removeData(const DATA_TYPE *data);
// note that b_sort is ignored
inline BOOL moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort);
inline BOOL moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort);
// resort -- use when the value we're sorting by changes
/* IW 12/6/02 - This doesn't work!
Instead, remove the data BEFORE you change it
Then re-insert it after you change it
BOOL resortData(DATA_TYPE *data)
*/
// remove all nodes from the list but do not delete data
inline void removeAllNodes();
inline BOOL deleteData(const DATA_TYPE *data);
// remove all nodes from the list and delete data
inline void deleteAllData();
// place mCurrentp on first node
inline void resetList();
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
inline DATA_TYPE *getCurrentData();
// same as getCurrentData() but a more intuitive name for the operation
inline DATA_TYPE *getNextData();
// remove the Node at mCurentOperatingp
// leave mCurrentp and mCurentOperatingp on the next entry
inline void removeCurrentData();
// delete the Node at mCurentOperatingp
// leave mCurrentp and mCurentOperatingp on the next entry
inline void deleteCurrentData();
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
inline DATA_TYPE *getFirstData();
// TRUE if nodes are not in sorted order
inline BOOL corrupt();
protected:
class LLPtrSkipNode
{
public:
LLPtrSkipNode()
: mData(NULL)
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mForward[i] = NULL;
}
}
LLPtrSkipNode(DATA_TYPE *data)
: mData(data)
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mForward[i] = NULL;
}
}
~LLPtrSkipNode()
{
if (mData)
{
llerror("Attempting to call LLPtrSkipNode destructor with a non-null mDatap!", 1);
}
}
// delete associated data and NULLs out pointer
void deleteData()
{
delete mData;
mData = NULL;
}
// NULLs out pointer
void removeData()
{
mData = NULL;
}
DATA_TYPE *mData;
LLPtrSkipNode *mForward[BINARY_DEPTH];
};
static BOOL defaultEquals(const DATA_TYPE *first, const DATA_TYPE *second)
{
return first == second;
}
LLPtrSkipNode mHead;
LLPtrSkipNode *mUpdate[BINARY_DEPTH];
LLPtrSkipNode *mCurrentp;
LLPtrSkipNode *mCurrentOperatingp;
S32 mLevel;
BOOL (*mInsertFirst)(const DATA_TYPE *first, const DATA_TYPE *second);
BOOL (*mEquals)(const DATA_TYPE *first, const DATA_TYPE *second);
};
// basic constructor
template <class DATA_TYPE, S32 BINARY_DEPTH>
LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList()
: mInsertFirst(NULL), mEquals(defaultEquals)
{
if (BINARY_DEPTH < 2)
{
llerrs << "Trying to create skip list with too little depth, "
"must be 2 or greater" << llendl;
}
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mUpdate[i] = NULL;
}
mLevel = 1;
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
// basic constructor including sorter
template <class DATA_TYPE, S32 BINARY_DEPTH>
LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second),
BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second))
:mInsertFirst(insert_first), mEquals(equals)
{
if (BINARY_DEPTH < 2)
{
llerrs << "Trying to create skip list with too little depth, "
"must be 2 or greater" << llendl;
}
mLevel = 1;
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mHead.mForward[i] = NULL;
mUpdate[i] = NULL;
}
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::~LLPtrSkipList()
{
removeAllNodes();
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second))
{
mInsertFirst = insert_first;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second))
{
mEquals = equals;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::addData(DATA_TYPE *data)
{
S32 level;
LLPtrSkipNode *current = &mHead;
LLPtrSkipNode *temp;
// find the pointer one in front of the one we want
if (mInsertFirst)
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(mInsertFirst(temp->mData, data)))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
else
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(temp->mData < data))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
// we're now just in front of where we want to be . . . take one step forward
current = *current->mForward;
// now add the new node
S32 newlevel;
for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
{
if (ll_frand() < 0.5f)
break;
}
LLPtrSkipNode *snode = new LLPtrSkipNode(data);
if (newlevel > mLevel)
{
mHead.mForward[mLevel] = NULL;
mUpdate[mLevel] = &mHead;
mLevel = newlevel;
}
for (level = 0; level < newlevel; level++)
{
snode->mForward[level] = mUpdate[level]->mForward[level];
mUpdate[level]->mForward[level] = snode;
}
return TRUE;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE *data)
{
S32 level;
LLPtrSkipNode *current = &mHead;
LLPtrSkipNode *temp;
// find the pointer one in front of the one we want
if (mInsertFirst)
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(mInsertFirst(temp->mData, data)))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
else
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(temp->mData < data))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
// we're now just in front of where we want to be . . . take one step forward
current = *current->mForward;
if (current)
{
return mEquals(current->mData, data);
}
else
{
return FALSE;
}
}
// returns number of items in the list
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline S32 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getLength()
{
U32 length = 0;
for (LLPtrSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
{
length++;
}
return length;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE *data)
{
S32 level;
LLPtrSkipNode *current = &mHead;
LLPtrSkipNode *temp;
// find the pointer one in front of the one we want
if (mInsertFirst)
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(mInsertFirst(temp->mData, data)))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
else
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(temp->mData < data))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
// we're now just in front of where we want to be . . . take one step forward
current = *current->mForward;
if (!current)
{
// empty list or beyond the end!
return FALSE;
}
// is this the one we want?
if (!mEquals(current->mData, data))
{
// nope!
return FALSE;
}
else
{
// yes it is! change pointers as required
for (level = 0; level < mLevel; level++)
{
if (mUpdate[level]->mForward[level] != current)
{
// cool, we've fixed all the pointers!
break;
}
mUpdate[level]->mForward[level] = current->mForward[level];
}
// clean up cuurent
current->removeData();
delete current;
// clean up mHead
while ( (mLevel > 1)
&&(!mHead.mForward[mLevel - 1]))
{
mLevel--;
}
}
return TRUE;
}
// note that b_sort is ignored
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort)
{
BOOL removed = removeData(data);
BOOL added = newlist->addData(data);
return removed && added;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort)
{
if (mCurrentOperatingp)
{
mCurrentp = mCurrentOperatingp->mForward[0];
BOOL removed = removeData(mCurrentOperatingp);
BOOL added = newlist->addData(mCurrentOperatingp);
mCurrentOperatingp = mCurrentp;
return removed && added;
}
return FALSE;
}
// resort -- use when the value we're sorting by changes
/* IW 12/6/02 - This doesn't work!
Instead, remove the data BEFORE you change it
Then re-insert it after you change it
BOOL resortData(DATA_TYPE *data)
{
removeData(data);
addData(data);
}
*/
// remove all nodes from the list but do not delete data
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
{
LLPtrSkipNode *temp;
// reset mCurrentp
mCurrentp = *(mHead.mForward);
while (mCurrentp)
{
temp = mCurrentp->mForward[0];
mCurrentp->removeData();
delete mCurrentp;
mCurrentp = temp;
}
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mHead.mForward[i] = NULL;
mUpdate[i] = NULL;
}
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteData(const DATA_TYPE *data)
{
S32 level;
LLPtrSkipNode *current = &mHead;
LLPtrSkipNode *temp;
// find the pointer one in front of the one we want
if (mInsertFirst)
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(mInsertFirst(temp->mData, data)))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
else
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(temp->mData < data))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
// we're now just in front of where we want to be . . . take one step forward
current = *current->mForward;
if (!current)
{
// empty list or beyond the end!
return FALSE;
}
// is this the one we want?
if (!mEquals(current->mData, data))
{
// nope!
return FALSE;
}
else
{
// do we need to fix current or currentop?
if (current == mCurrentp)
{
mCurrentp = current->mForward[0];
}
if (current == mCurrentOperatingp)
{
mCurrentOperatingp = current->mForward[0];
}
// yes it is! change pointers as required
for (level = 0; level < mLevel; level++)
{
if (mUpdate[level]->mForward[level] != current)
{
// cool, we've fixed all the pointers!
break;
}
mUpdate[level]->mForward[level] = current->mForward[level];
}
// clean up cuurent
current->deleteData();
delete current;
// clean up mHead
while ( (mLevel > 1)
&&(!mHead.mForward[mLevel - 1]))
{
mLevel--;
}
}
return TRUE;
}
// remove all nodes from the list and delete data
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteAllData()
{
LLPtrSkipNode *temp;
// reset mCurrentp
mCurrentp = *(mHead.mForward);
while (mCurrentp)
{
temp = mCurrentp->mForward[0];
mCurrentp->deleteData();
delete mCurrentp;
mCurrentp = temp;
}
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mHead.mForward[i] = NULL;
mUpdate[i] = NULL;
}
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
// place mCurrentp on first node
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::resetList()
{
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
{
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = *mCurrentp->mForward;
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return 0; // equivalent, but no warning
}
}
// same as getCurrentData() but a more intuitive name for the operation
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
{
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = *mCurrentp->mForward;
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return 0; // equivalent, but no warning
}
}
// remove the Node at mCurentOperatingp
// leave mCurrentp and mCurentOperatingp on the next entry
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
{
if (mCurrentOperatingp)
{
removeData(mCurrentOperatingp->mData);
}
}
// delete the Node at mCurentOperatingp
// leave mCurrentp and mCurentOperatingp on the next entry
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteCurrentData()
{
if (mCurrentOperatingp)
{
deleteData(mCurrentOperatingp->mData);
}
}
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData()
{
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = mCurrentp->mForward[0];
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return 0; // equivalent, but no warning
}
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::corrupt()
{
LLPtrSkipNode *previous = mHead.mForward[0];
// Empty lists are not corrupt.
if (!previous) return FALSE;
LLPtrSkipNode *current = previous->mForward[0];
while(current)
{
if (!mInsertFirst(previous->mData, current->mData))
{
// prev shouldn't be in front of cur!
return TRUE;
}
current = current->mForward[0];
}
return FALSE;
}
#endif

File diff suppressed because it is too large Load Diff

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
{
@ -403,6 +404,7 @@ S32 LLQueuedThread::processNextRequest()
QueuedRequest *req;
// Get next request from pool
lockData();
while(1)
{
req = NULL;
@ -467,10 +469,11 @@ S32 LLQueuedThread::processNextRequest()
ms_sleep(1); // sleep the thread a little
}
}
LLTrace::get_thread_recorder()->pushToMaster();
}
S32 pending = getPending();
return pending;
}
@ -499,6 +502,7 @@ void LLQueuedThread::run()
if (isQuitting())
{
LLTrace::get_thread_recorder()->pushToMaster();
endThread();
break;
}
@ -507,8 +511,9 @@ void LLQueuedThread::run()
threadedUpdate();
int res = processNextRequest();
if (res == 0)
int pending_work = processNextRequest();
if (pending_work == 0)
{
mIdleThread = TRUE;
ms_sleep(1);

View File

@ -29,7 +29,6 @@
#include <list>
#include <boost/type_traits.hpp>
#include "llsingleton.h"
#include "llstl.h"
@ -47,12 +46,11 @@ template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultC
class LLRegistry
{
public:
typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
typedef typename boost::add_reference<typename boost::add_const<KEY>::type>::type ref_const_key_t;
typedef typename boost::add_reference<typename boost::add_const<VALUE>::type>::type ref_const_value_t;
typedef typename boost::add_reference<VALUE>::type ref_value_t;
typedef typename boost::add_pointer<typename boost::add_const<VALUE>::type>::type ptr_const_value_t;
typedef typename boost::add_pointer<VALUE>::type ptr_value_t;
typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
typedef const KEY& ref_const_key_t;
typedef const VALUE& ref_const_value_t;
typedef const VALUE* ptr_const_value_t;
typedef VALUE* ptr_value_t;
class Registrar
{

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()
@ -299,6 +299,7 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd)
LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t();
readSDValues(cb, sd, stack);
}
namespace LLInitParam
{
// LLSD specialization
@ -329,13 +330,14 @@ namespace LLInitParam
p.writeValue<LLSD::String>(sd.asString(), name_stack);
}
void ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const
bool ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const
{
// attempt to write LLSD out directly
if (!p.writeValue<LLSD>(mValue, name_stack))
if (!p.writeValue<LLSD>(mValue, name_stack_range))
{
// 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);
LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack_range);
}
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

@ -28,5 +28,4 @@
#include "llsingleton.h"
std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;

View File

@ -30,38 +30,6 @@
#include <typeinfo>
#include <boost/noncopyable.hpp>
/// @brief A global registry of all singletons to prevent duplicate allocations
/// across shared library boundaries
class LL_COMMON_API LLSingletonRegistry {
private:
typedef std::map<std::string, void *> TypeMap;
static TypeMap * sSingletonMap;
static void checkInit()
{
if(sSingletonMap == NULL)
{
sSingletonMap = new TypeMap();
}
}
public:
template<typename T> static void * & get()
{
std::string name(typeid(T).name());
checkInit();
// the first entry of the pair returned by insert will be either the existing
// iterator matching our key, or the newly inserted NULL initialized entry
// see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
TypeMap::iterator result =
sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
return result->second;
}
};
// LLSingleton implements the getInstance() method part of the Singleton
// pattern. It can't make the derived class constructors protected, though, so
// you have to do that yourself.
@ -99,22 +67,30 @@ private:
INITIALIZED,
DELETED
} EInitState;
static DERIVED_TYPE* constructSingleton()
{
return new DERIVED_TYPE();
}
// stores pointer to singleton instance
// and tracks initialization state of singleton
struct SingletonInstanceData
struct SingletonLifetimeManager
{
EInitState mInitState;
DERIVED_TYPE* mSingletonInstance;
SingletonInstanceData()
: mSingletonInstance(NULL),
mInitState(UNINITIALIZED)
{}
~SingletonInstanceData()
SingletonLifetimeManager()
{
if (mInitState != DELETED)
construct();
}
static void construct()
{
sData.mInitState = CONSTRUCTING;
sData.mInstance = constructSingleton();
sData.mInitState = INITIALIZING;
}
~SingletonLifetimeManager()
{
if (sData.mInitState != DELETED)
{
deleteSingleton();
}
@ -124,9 +100,8 @@ private:
public:
virtual ~LLSingleton()
{
SingletonInstanceData& data = getData();
data.mSingletonInstance = NULL;
data.mInitState = DELETED;
sData.mInstance = NULL;
sData.mInitState = DELETED;
}
/**
@ -151,50 +126,49 @@ public:
*/
static void deleteSingleton()
{
delete getData().mSingletonInstance;
getData().mSingletonInstance = NULL;
getData().mInitState = DELETED;
delete sData.mInstance;
sData.mInstance = NULL;
sData.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);
}
static DERIVED_TYPE* getInstance()
{
SingletonInstanceData& data = getData();
static SingletonLifetimeManager sLifeTimeMgr;
if (data.mInitState == CONSTRUCTING)
switch (sData.mInitState)
{
case UNINITIALIZED:
// should never be uninitialized at this point
llassert(false);
return NULL;
case CONSTRUCTING:
llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
return NULL;
case INITIALIZING:
// go ahead and flag ourselves as initialized so we can be reentrant during initialization
sData.mInitState = INITIALIZED;
// initialize singleton after constructing it so that it can reference other singletons which in turn depend on it,
// thus breaking cyclic dependencies
sData.mInstance->initSingleton();
return sData.mInstance;
case INITIALIZED:
return sData.mInstance;
case DELETED:
llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
SingletonLifetimeManager::construct();
// same as first time construction
sData.mInitState = INITIALIZED;
sData.mInstance->initSingleton();
return sData.mInstance;
}
if (data.mInitState == DELETED)
{
llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
}
if (!data.mSingletonInstance)
{
data.mInitState = CONSTRUCTING;
data.mSingletonInstance = new DERIVED_TYPE();
data.mInitState = INITIALIZING;
data.mSingletonInstance->initSingleton();
data.mInitState = INITIALIZED;
}
return data.mSingletonInstance;
return NULL;
}
static DERIVED_TYPE* getIfExists()
{
return sData.mInstance;
}
// Reference version of getInstance()
@ -208,18 +182,31 @@ public:
// Use this to avoid accessing singletons before the can safely be constructed
static bool instanceExists()
{
return getData().mInitState == INITIALIZED;
return sData.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 sData.mInitState == DELETED;
}
private:
virtual void initSingleton() {}
struct SingletonData
{
// explicitly has a default constructor so that member variables are zero initialized in BSS
// and only changed by singleton logic, not constructor running during startup
EInitState mInitState;
DERIVED_TYPE* mInstance;
};
static SingletonData sData;
};
template<typename T>
typename LLSingleton<T>::SingletonData LLSingleton<T>::sData;
#endif

View File

@ -1,517 +0,0 @@
/**
* @file llskiplist.h
* @brief skip list implementation
*
* $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_LLSKIPLIST_H
#define LL_LLSKIPLIST_H
#include "llrand.h"
#include "llrand.h"
// NOTA BENE: Insert first needs to be < NOT <=
// Binary depth must be >= 2
template <class DATA_TYPE, S32 BINARY_DEPTH = 10>
class LLSkipList
{
public:
typedef BOOL (*compare)(const DATA_TYPE& first, const DATA_TYPE& second);
typedef compare insert_func;
typedef compare equals_func;
void init();
// basic constructor
LLSkipList();
// basic constructor including sorter
LLSkipList(insert_func insert_first, equals_func equals);
~LLSkipList();
inline void setInsertFirst(insert_func insert_first);
inline void setEquals(equals_func equals);
inline BOOL addData(const DATA_TYPE& data);
inline BOOL checkData(const DATA_TYPE& data);
// returns number of items in the list
inline S32 getLength() const; // NOT a constant time operation, traverses entire list!
inline BOOL moveData(const DATA_TYPE& data, LLSkipList *newlist);
inline BOOL removeData(const DATA_TYPE& data);
// remove all nodes from the list but do not delete data
inline void removeAllNodes();
// place mCurrentp on first node
inline void resetList();
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
inline DATA_TYPE getCurrentData();
// same as getCurrentData() but a more intuitive name for the operation
inline DATA_TYPE getNextData();
// remove the Node at mCurentOperatingp
// leave mCurrentp and mCurentOperatingp on the next entry
inline void removeCurrentData();
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
inline DATA_TYPE getFirstData();
class LLSkipNode
{
public:
LLSkipNode()
: mData(0)
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mForward[i] = NULL;
}
}
LLSkipNode(DATA_TYPE data)
: mData(data)
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mForward[i] = NULL;
}
}
~LLSkipNode()
{
}
DATA_TYPE mData;
LLSkipNode *mForward[BINARY_DEPTH];
private:
// Disallow copying of LLSkipNodes by not implementing these methods.
LLSkipNode(const LLSkipNode &);
LLSkipNode &operator=(const LLSkipNode &);
};
static BOOL defaultEquals(const DATA_TYPE& first, const DATA_TYPE& second)
{
return first == second;
}
private:
LLSkipNode mHead;
LLSkipNode *mUpdate[BINARY_DEPTH];
LLSkipNode *mCurrentp;
LLSkipNode *mCurrentOperatingp;
S32 mLevel;
insert_func mInsertFirst;
equals_func mEquals;
private:
// Disallow copying of LLSkipNodes by not implementing these methods.
LLSkipList(const LLSkipList &);
LLSkipList &operator=(const LLSkipList &);
};
///////////////////////
//
// Implementation
//
// Binary depth must be >= 2
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::init()
{
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mHead.mForward[i] = NULL;
mUpdate[i] = NULL;
}
mLevel = 1;
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
// basic constructor
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList()
: mInsertFirst(NULL),
mEquals(defaultEquals)
{
init();
}
// basic constructor including sorter
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList(insert_func insert,
equals_func equals)
: mInsertFirst(insert),
mEquals(equals)
{
init();
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::~LLSkipList()
{
removeAllNodes();
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(insert_func insert_first)
{
mInsertFirst = insert_first;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(equals_func equals)
{
mEquals = equals;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::addData(const DATA_TYPE& data)
{
S32 level;
LLSkipNode *current = &mHead;
LLSkipNode *temp;
// find the pointer one in front of the one we want
if (mInsertFirst)
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(mInsertFirst(temp->mData, data)))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
else
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(temp->mData < data))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
// we're now just in front of where we want to be . . . take one step forward
current = *current->mForward;
// now add the new node
S32 newlevel;
for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++)
{
if (ll_frand() < 0.5f)
break;
}
LLSkipNode *snode = new LLSkipNode(data);
if (newlevel > mLevel)
{
mHead.mForward[mLevel] = NULL;
mUpdate[mLevel] = &mHead;
mLevel = newlevel;
}
for (level = 0; level < newlevel; level++)
{
snode->mForward[level] = mUpdate[level]->mForward[level];
mUpdate[level]->mForward[level] = snode;
}
return TRUE;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE& data)
{
S32 level;
LLSkipNode *current = &mHead;
LLSkipNode *temp;
// find the pointer one in front of the one we want
if (mInsertFirst)
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(mInsertFirst(temp->mData, data)))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
else
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(temp->mData < data))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
// we're now just in front of where we want to be . . . take one step forward
current = *current->mForward;
if (current)
{
return mEquals(current->mData, data);
}
return FALSE;
}
// returns number of items in the list
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline S32 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() const
{
U32 length = 0;
for (LLSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0])
{
length++;
}
return length;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE& data, LLSkipList *newlist)
{
BOOL removed = removeData(data);
BOOL added = newlist->addData(data);
return removed && added;
}
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE& data)
{
S32 level;
LLSkipNode *current = &mHead;
LLSkipNode *temp;
// find the pointer one in front of the one we want
if (mInsertFirst)
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(mInsertFirst(temp->mData, data)))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
else
{
for (level = mLevel - 1; level >= 0; level--)
{
temp = *(current->mForward + level);
while ( (temp)
&&(temp->mData < data))
{
current = temp;
temp = *(current->mForward + level);
}
*(mUpdate + level) = current;
}
}
// we're now just in front of where we want to be . . . take one step forward
current = *current->mForward;
if (!current)
{
// empty list or beyond the end!
return FALSE;
}
// is this the one we want?
if (!mEquals(current->mData, data))
{
// nope!
return FALSE;
}
else
{
// do we need to fix current or currentop?
if (current == mCurrentp)
{
mCurrentp = current->mForward[0];
}
if (current == mCurrentOperatingp)
{
mCurrentOperatingp = current->mForward[0];
}
// yes it is! change pointers as required
for (level = 0; level < mLevel; level++)
{
if (mUpdate[level]->mForward[level] != current)
{
// cool, we've fixed all the pointers!
break;
}
mUpdate[level]->mForward[level] = current->mForward[level];
}
// clean up cuurent
delete current;
// clean up mHead
while ( (mLevel > 1)
&&(!mHead.mForward[mLevel - 1]))
{
mLevel--;
}
}
return TRUE;
}
// remove all nodes from the list but do not delete data
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes()
{
LLSkipNode *temp;
// reset mCurrentp
mCurrentp = *(mHead.mForward);
while (mCurrentp)
{
temp = mCurrentp->mForward[0];
delete mCurrentp;
mCurrentp = temp;
}
S32 i;
for (i = 0; i < BINARY_DEPTH; i++)
{
mHead.mForward[i] = NULL;
mUpdate[i] = NULL;
}
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
// place mCurrentp on first node
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::resetList()
{
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
}
// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData()
{
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = mCurrentp->mForward[0];
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return (DATA_TYPE)0; // equivalent, but no warning
}
}
// same as getCurrentData() but a more intuitive name for the operation
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData()
{
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = mCurrentp->mForward[0];
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return (DATA_TYPE)0; // equivalent, but no warning
}
}
// remove the Node at mCurentOperatingp
// leave mCurrentp and mCurentOperatingp on the next entry
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData()
{
if (mCurrentOperatingp)
{
removeData(mCurrentOperatingp->mData);
}
}
// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp
template <class DATA_TYPE, S32 BINARY_DEPTH>
inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData()
{
mCurrentp = *(mHead.mForward);
mCurrentOperatingp = *(mHead.mForward);
if (mCurrentp)
{
mCurrentOperatingp = mCurrentp;
mCurrentp = mCurrentp->mForward[0];
return mCurrentOperatingp->mData;
}
else
{
//return NULL; // causes compile warning
return (DATA_TYPE)0; // equivalent, but no warning
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +0,0 @@
/**
* @file llsortedvector.h
* @author Nat Goodspeed
* @date 2012-04-08
* @brief LLSortedVector class wraps a vector that we maintain in sorted
* order so we can perform binary-search lookups.
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Copyright (c) 2012, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLSORTEDVECTOR_H)
#define LL_LLSORTEDVECTOR_H
#include <vector>
#include <algorithm>
/**
* LLSortedVector contains a std::vector<std::pair> that we keep sorted on the
* first of the pair. This makes insertion somewhat more expensive than simple
* std::vector::push_back(), but allows us to use binary search for lookups.
* It's intended for small aggregates where lookup is far more performance-
* critical than insertion; in such cases a binary search on a small, sorted
* std::vector can be more performant than a std::map lookup.
*/
template <typename KEY, typename VALUE>
class LLSortedVector
{
public:
typedef LLSortedVector<KEY, VALUE> self;
typedef KEY key_type;
typedef VALUE mapped_type;
typedef std::pair<key_type, mapped_type> value_type;
typedef std::vector<value_type> PairVector;
typedef typename PairVector::iterator iterator;
typedef typename PairVector::const_iterator const_iterator;
/// Empty
LLSortedVector() {}
/// Fixed initial size
LLSortedVector(std::size_t size):
mVector(size)
{}
/// Bulk load
template <typename ITER>
LLSortedVector(ITER begin, ITER end):
mVector(begin, end)
{
// Allow caller to dump in a bunch of (pairs convertible to)
// value_type if desired, but make sure we sort afterwards.
std::sort(mVector.begin(), mVector.end());
}
/// insert(key, value)
std::pair<iterator, bool> insert(const key_type& key, const mapped_type& value)
{
return insert(value_type(key, value));
}
/// insert(value_type)
std::pair<iterator, bool> insert(const value_type& pair)
{
typedef std::pair<iterator, bool> iterbool;
iterator found = std::lower_bound(mVector.begin(), mVector.end(), pair,
less<value_type>());
// have to check for end() before it's even valid to dereference
if (found == mVector.end())
{
std::size_t index(mVector.size());
mVector.push_back(pair);
// don't forget that push_back() invalidates 'found'
return iterbool(mVector.begin() + index, true);
}
if (found->first == pair.first)
{
return iterbool(found, false);
}
// remember that insert() invalidates 'found' -- save index
std::size_t index(found - mVector.begin());
mVector.insert(found, pair);
// okay, convert from index back to iterator
return iterbool(mVector.begin() + index, true);
}
iterator begin() { return mVector.begin(); }
iterator end() { return mVector.end(); }
const_iterator begin() const { return mVector.begin(); }
const_iterator end() const { return mVector.end(); }
bool empty() const { return mVector.empty(); }
std::size_t size() const { return mVector.size(); }
/// find
iterator find(const key_type& key)
{
iterator found = std::lower_bound(mVector.begin(), mVector.end(),
value_type(key, mapped_type()),
less<value_type>());
if (found == mVector.end() || found->first != key)
return mVector.end();
return found;
}
const_iterator find(const key_type& key) const
{
return const_cast<self*>(this)->find(key);
}
private:
// Define our own 'less' comparator so we can specialize without messing
// with std::less.
template <typename T>
struct less: public std::less<T> {};
// Specialize 'less' for an LLSortedVector::value_type involving
// std::type_info*. This is one of LLSortedVector's foremost use cases. We
// specialize 'less' rather than just defining a specific comparator
// because LLSortedVector should be usable for other key_types as well.
template <typename T>
struct less< std::pair<std::type_info*, T> >:
public std::binary_function<std::pair<std::type_info*, T>,
std::pair<std::type_info*, T>,
bool>
{
bool operator()(const std::pair<std::type_info*, T>& lhs,
const std::pair<std::type_info*, T>& rhs) const
{
return lhs.first->before(*rhs.first);
}
};
// Same as above, but with const std::type_info*.
template <typename T>
struct less< std::pair<const std::type_info*, T> >:
public std::binary_function<std::pair<const std::type_info*, T>,
std::pair<const std::type_info*, T>,
bool>
{
bool operator()(const std::pair<const std::type_info*, T>& lhs,
const std::pair<const std::type_info*, T>& rhs) const
{
return lhs.first->before(*rhs.first);
}
};
PairVector mVector;
};
#endif /* ! defined(LL_LLSORTEDVECTOR_H) */

View File

@ -1,48 +0,0 @@
/**
* @file llstack.h
* @brief LLStack template class
*
* $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_LLSTACK_H
#define LL_LLSTACK_H
#include "linked_lists.h"
template <class DATA_TYPE> class LLStack
{
private:
LLLinkedList<DATA_TYPE> mStack;
public:
LLStack() {}
~LLStack() {}
void push(DATA_TYPE *data) { mStack.addData(data); }
DATA_TYPE *pop() { DATA_TYPE *tempp = mStack.getFirstData(); mStack.removeCurrentData(); return tempp; }
void deleteAllData() { mStack.deleteAllData(); }
void removeAllNodes() { mStack.removeAllNodes(); }
};
#endif

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(LLTrace::getUIThreadRecorder());
#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

@ -31,20 +31,14 @@
#include "llapr.h"
#include "apr_thread_cond.h"
#include "boost/intrusive_ptr.hpp"
#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:
@ -98,15 +92,15 @@ private:
BOOL mPaused;
// static function passed to APR thread creation routine
static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap);
protected:
std::string mName;
LLCondition* mRunCondition;
class LLCondition* mRunCondition;
LLMutex* mDataLock;
apr_thread_t *mAPRThreadp;
apr_pool_t *mAPRPoolp;
apr_thread_t* mAPRThreadp;
apr_pool_t* mAPRPoolp;
BOOL mIsLocalPool;
EThreadStatus mStatus;
U32 mID;
@ -114,7 +108,7 @@ protected:
//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
// otherwise it will cause severe memory leaking!!! --bao
LLVolatileAPRPool *mLocalAPRFilePoolp ;
LLVolatileAPRPool* mLocalAPRFilePoolp ;
void setQuitting();
@ -140,75 +134,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,117 @@
/**
* @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"
#include "llapr.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::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 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,357 @@
/**
* @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"
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);
void* get() const;
void initStorage();
void destroyStorage();
protected:
struct 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;
}
bool isNull() const { return !sInitialized || get() == NULL; }
bool notNull() const { return sInitialized && get() != NULL; }
};
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:
LL_FORCE_INLINE static DERIVED_TYPE* getInstance()
{
#if LL_DARWIN
createTLSKey();
return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey);
#else
return sInstance;
#endif
}
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<U64, LLUnits::Microseconds> LLTimer::getTotalTime()
{
// simply call into the implementation function.
return totalTime();
}
// static
F64 LLTimer::getTotalSeconds()
LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getTotalSeconds()
{
return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;
}
@ -343,23 +341,23 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount)
}
F64 LLTimer::getElapsedTimeF64() const
LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getElapsedTimeF64() const
{
U64 last = mLastClockCount;
return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;
}
F32 LLTimer::getElapsedTimeF32() const
LLUnitImplicit<F32, LLUnits::Seconds> LLTimer::getElapsedTimeF32() const
{
return (F32)getElapsedTimeF64();
}
F64 LLTimer::getElapsedTimeAndResetF64()
LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getElapsedTimeAndResetF64()
{
return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;
}
F32 LLTimer::getElapsedTimeAndResetF32()
LLUnitImplicit<F32, LLUnits::Seconds> LLTimer::getElapsedTimeAndResetF32()
{
return (F32)getElapsedTimeAndResetF64();
}
@ -372,7 +370,7 @@ void LLTimer::setTimerExpirySec(F32 expiration)
+ (U64)((F32)(expiration * gClockFrequency));
}
F32 LLTimer::getRemainingTimeF32() const
LLUnitImplicit<F32, LLUnits::Seconds> 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<F64, LLUnits::Seconds> getElapsedSeconds()
{
return sTimer->getElapsedTimeF64();
}
// Return a high precision usec since epoch
static U64 getTotalTime();
static LLUnitImplicit<U64, LLUnits::Microseconds> getTotalTime();
// Return a high precision seconds since epoch
static F64 getTotalSeconds();
static LLUnitImplicit<F64, LLUnits::Seconds> 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<F32, LLUnits::Seconds> getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
LLUnitImplicit<F64, LLUnits::Seconds> getElapsedTimeAndResetF64();
F32 getRemainingTimeF32() const;
LLUnitImplicit<F32, LLUnits::Seconds> getRemainingTimeF32() const;
static BOOL knownBadTimer();
// ACCESSORS
F32 getElapsedTimeF32() const; // Returns elapsed time in seconds
F64 getElapsedTimeF64() const; // Returns elapsed time in seconds
LLUnitImplicit<F32, LLUnits::Seconds> getElapsedTimeF32() const; // Returns elapsed time in seconds
LLUnitImplicit<F64, LLUnits::Seconds> getElapsedTimeF64() const; // Returns elapsed time in seconds
BOOL getStarted() const { return mStarted; }
bool getStarted() const { return mStarted; }
static U64 getCurrentClockCount(); // Returns the raw clockticks

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

@ -0,0 +1,116 @@
/**
* @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* gUIThreadRecorder = NULL;
void init()
{
if (sInitializationCount++ == 0)
{
gUIThreadRecorder = new MasterThreadRecorder();
}
}
bool isInitialized()
{
return sInitializationCount > 0;
}
void cleanup()
{
if (--sInitializationCount == 0)
{
delete gUIThreadRecorder;
gUIThreadRecorder = NULL;
}
}
MasterThreadRecorder& getUIThreadRecorder()
{
llassert(gUIThreadRecorder != NULL);
return *gUIThreadRecorder;
}
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),
mCollapsed(true)
{}
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;
}
}

1099
indra/llcommon/lltrace.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,914 @@
/**
* @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()
{}
void RecordingBuffers::handOffTo(RecordingBuffers& other)
{
other.mCounts.reset(&mCounts);
other.mSamples.reset(&mSamples);
other.mEvents.reset(&mEvents);
other.mStackTimers.reset(&mStackTimers);
other.mMemStats.reset(&mMemStats);
}
void RecordingBuffers::makePrimary()
{
mCounts.makePrimary();
mSamples.makePrimary();
mEvents.makePrimary();
mStackTimers.makePrimary();
mMemStats.makePrimary();
ThreadRecorder* thread_recorder = get_thread_recorder().get();
AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers;
// 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::append( const RecordingBuffers& other )
{
mCounts.addSamples(other.mCounts);
mSamples.addSamples(other.mSamples);
mEvents.addSamples(other.mEvents);
mMemStats.addSamples(other.mMemStats);
mStackTimers.addSamples(other.mStackTimers);
}
void RecordingBuffers::merge( const RecordingBuffers& other)
{
mCounts.addSamples(other.mCounts, false);
mSamples.addSamples(other.mSamples, false);
mEvents.addSamples(other.mEvents, false);
mMemStats.addSamples(other.mMemStats, false);
// for now, hold out timers from merge, need to be displayed per thread
//mStackTimers.addSamples(other.mStackTimers, false);
}
void RecordingBuffers::reset(RecordingBuffers* other)
{
mCounts.reset(other ? &other->mCounts : NULL);
mSamples.reset(other ? &other->mSamples : NULL);
mEvents.reset(other ? &other->mEvents : NULL);
mStackTimers.reset(other ? &other->mStackTimers : NULL);
mMemStats.reset(other ? &other->mMemStats : NULL);
}
void RecordingBuffers::flush()
{
LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds();
mSamples.flush(time_stamp);
}
///////////////////////////////////////////////////////////////////////
// Recording
///////////////////////////////////////////////////////////////////////
Recording::Recording()
: mElapsedSeconds(0)
{
mBuffers = new RecordingBuffers();
}
Recording::Recording( const Recording& other )
{
*this = other;
}
Recording& Recording::operator = (const Recording& other)
{
// this will allow us to seamlessly start without affecting any data we've acquired from other
setPlayState(PAUSED);
Recording& mutable_other = const_cast<Recording&>(other);
mutable_other.update();
EPlayState other_play_state = other.getPlayState();
mBuffers = mutable_other.mBuffers;
LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state);
// above call will clear mElapsedSeconds as a side effect, so copy it here
mElapsedSeconds = other.mElapsedSeconds;
mSamplingTimer = other.mSamplingTimer;
return *this;
}
Recording::~Recording()
{
if (isStarted() && LLTrace::get_thread_recorder().notNull())
{
LLTrace::get_thread_recorder()->deactivate(this);
}
}
void Recording::update()
{
if (isStarted())
{
mBuffers.write()->flush();
LLTrace::get_thread_recorder()->bringUpToDate(this);
mSamplingTimer.reset();
}
}
void Recording::handleReset()
{
mBuffers.write()->reset();
mElapsedSeconds = 0.0;
mSamplingTimer.reset();
}
void Recording::handleStart()
{
mSamplingTimer.reset();
LLTrace::get_thread_recorder()->activate(this);
}
void Recording::handleStop()
{
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
mBuffers.write()->flush();
LLTrace::get_thread_recorder()->deactivate(this);
}
void Recording::handleSplitTo(Recording& other)
{
mBuffers.write()->handOffTo(*other.mBuffers.write());
}
void Recording::appendRecording( const Recording& other )
{
update();
mBuffers.write()->append(*other.mBuffers);
mElapsedSeconds += other.mElapsedSeconds;
}
void Recording::mergeRecording( const Recording& other)
{
update();
mBuffers.write()->merge(*other.mBuffers);
}
LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat)
{
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
/ (F64)LLTrace::TimeBlock::countsPerSecond();
}
LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat)
{
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
return (F64)(accumulator.mSelfTimeCounter) / (F64)LLTrace::TimeBlock::countsPerSecond();
}
U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat)
{
return mBuffers->mStackTimers[stat.getIndex()].mCalls;
}
LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat)
{
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value());
}
LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat)
{
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
return (F64)(accumulator.mSelfTimeCounter)
/ ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value());
}
F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat)
{
return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds.value();
}
LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mSize.getMin();
}
LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mSize.getMean();
}
LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mSize.getMax();
}
LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mSize.getStandardDeviation();
}
LLUnit<F64, LLUnits::Bytes> Recording::getLastValue(const TraceType<MemStatAccumulator>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mSize.getLastValue();
}
LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMin();
}
LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMean();
}
LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMax();
}
LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getStandardDeviation();
}
LLUnit<F64, LLUnits::Bytes> Recording::getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mChildSize.getLastValue();
}
U32 Recording::getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount;
}
U32 Recording::getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat)
{
return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount;
}
F64 Recording::getSum( const TraceType<CountAccumulator>& stat )
{
return mBuffers->mCounts[stat.getIndex()].getSum();
}
F64 Recording::getSum( const TraceType<EventAccumulator>& stat )
{
return (F64)mBuffers->mEvents[stat.getIndex()].getSum();
}
F64 Recording::getPerSec( const TraceType<CountAccumulator>& stat )
{
F64 sum = mBuffers->mCounts[stat.getIndex()].getSum();
return (sum != 0.0)
? (sum / mElapsedSeconds.value())
: 0.0;
}
U32 Recording::getSampleCount( const TraceType<CountAccumulator>& stat )
{
return mBuffers->mCounts[stat.getIndex()].getSampleCount();
}
F64 Recording::getMin( const TraceType<SampleAccumulator>& stat )
{
return mBuffers->mSamples[stat.getIndex()].getMin();
}
F64 Recording::getMax( const TraceType<SampleAccumulator>& stat )
{
return mBuffers->mSamples[stat.getIndex()].getMax();
}
F64 Recording::getMean( const TraceType<SampleAccumulator>& stat )
{
return mBuffers->mSamples[stat.getIndex()].getMean();
}
F64 Recording::getStandardDeviation( const TraceType<SampleAccumulator>& stat )
{
return mBuffers->mSamples[stat.getIndex()].getStandardDeviation();
}
F64 Recording::getLastValue( const TraceType<SampleAccumulator>& stat )
{
return mBuffers->mSamples[stat.getIndex()].getLastValue();
}
U32 Recording::getSampleCount( const TraceType<SampleAccumulator>& stat )
{
return mBuffers->mSamples[stat.getIndex()].getSampleCount();
}
F64 Recording::getMin( const TraceType<EventAccumulator>& stat )
{
return mBuffers->mEvents[stat.getIndex()].getMin();
}
F64 Recording::getMax( const TraceType<EventAccumulator>& stat )
{
return mBuffers->mEvents[stat.getIndex()].getMax();
}
F64 Recording::getMean( const TraceType<EventAccumulator>& stat )
{
return mBuffers->mEvents[stat.getIndex()].getMean();
}
F64 Recording::getStandardDeviation( const TraceType<EventAccumulator>& stat )
{
return mBuffers->mEvents[stat.getIndex()].getStandardDeviation();
}
F64 Recording::getLastValue( const TraceType<EventAccumulator>& stat )
{
return mBuffers->mEvents[stat.getIndex()].getLastValue();
}
U32 Recording::getSampleCount( const TraceType<EventAccumulator>& stat )
{
return mBuffers->mEvents[stat.getIndex()].getSampleCount();
}
///////////////////////////////////////////////////////////////////////
// PeriodicRecording
///////////////////////////////////////////////////////////////////////
PeriodicRecording::PeriodicRecording( U32 num_periods, EPlayState state)
: mAutoResize(num_periods == 0),
mCurPeriod(0),
mNumPeriods(0),
mRecordingPeriods(num_periods ? num_periods : 1)
{
setPlayState(state);
}
void PeriodicRecording::nextPeriod()
{
if (mAutoResize)
{
mRecordingPeriods.push_back(Recording());
}
Recording& old_recording = getCurRecording();
mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size();
old_recording.splitTo(getCurRecording());
mNumPeriods = llmin(mRecordingPeriods.size(), mNumPeriods + 1);
}
void PeriodicRecording::appendRecording(Recording& recording)
{
getCurRecording().appendRecording(recording);
nextPeriod();
}
void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
{
if (other.mRecordingPeriods.empty()) return;
getCurRecording().update();
other.getCurRecording().update();
const U32 other_recording_slots = other.mRecordingPeriods.size();
const U32 other_num_recordings = other.getNumRecordedPeriods();
const U32 other_current_recording_index = other.mCurPeriod;
const U32 other_oldest_recording_index = (other_current_recording_index + other_recording_slots - other_num_recordings + 1) % other_recording_slots;
// append first recording into our current slot
getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]);
// from now on, add new recordings for everything after the first
U32 other_index = (other_oldest_recording_index + 1) % other_recording_slots;
if (mAutoResize)
{
// append first recording into our current slot
getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]);
// push back recordings for everything in the middle
U32 other_index = (other_oldest_recording_index + 1) % other_recording_slots;
while (other_index != other_current_recording_index)
{
mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]);
other_index = (other_index + 1) % other_recording_slots;
}
// add final recording, if it wasn't already added as the first
if (other_num_recordings > 1)
{
mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]);
}
mCurPeriod = mRecordingPeriods.size() - 1;
mNumPeriods = mRecordingPeriods.size();
}
else
{
size_t num_to_copy = llmin( mRecordingPeriods.size(), (size_t)other_num_recordings);
std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin() + other_index ;
std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + mCurPeriod;
// already consumed the first recording from other, so start counting at 1
for(size_t i = 1; i < num_to_copy; i++)
{
*dest_it = *src_it;
if (++src_it == other.mRecordingPeriods.end())
{
src_it = other.mRecordingPeriods.begin();
}
if (++dest_it == mRecordingPeriods.end())
{
dest_it = mRecordingPeriods.begin();
}
}
// want argument to % to be positive, otherwise result could be negative and thus out of bounds
llassert(num_to_copy >= 1);
// advance to last recording period copied, and make that our current period
mCurPeriod = (mCurPeriod + num_to_copy - 1) % mRecordingPeriods.size();
mNumPeriods = llmin(mRecordingPeriods.size(), mNumPeriods + num_to_copy - 1);
}
// end with fresh period, otherwise next appendPeriodicRecording() will merge the first
// recording period with the last one appended here
nextPeriod();
getCurRecording().setPlayState(getPlayState());
}
LLUnit<F64, LLUnits::Seconds> PeriodicRecording::getDuration() const
{
LLUnit<F64, LLUnits::Seconds> duration;
size_t num_periods = mRecordingPeriods.size();
for (size_t i = 1; i <= num_periods; i++)
{
size_t index = (mCurPeriod + num_periods - i) % num_periods;
duration += mRecordingPeriods[index].getDuration();
}
return duration;
}
LLTrace::Recording PeriodicRecording::snapshotCurRecording() const
{
Recording recording_copy(getCurRecording());
recording_copy.stop();
return recording_copy;
}
Recording& PeriodicRecording::getLastRecording()
{
return getPrevRecording(1);
}
const Recording& PeriodicRecording::getLastRecording() const
{
return getPrevRecording(1);
}
Recording& PeriodicRecording::getCurRecording()
{
return mRecordingPeriods[mCurPeriod];
}
const Recording& PeriodicRecording::getCurRecording() const
{
return mRecordingPeriods[mCurPeriod];
}
Recording& PeriodicRecording::getPrevRecording( U32 offset )
{
U32 num_periods = mRecordingPeriods.size();
offset = llclamp(offset, 0u, num_periods - 1);
return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
}
const Recording& PeriodicRecording::getPrevRecording( U32 offset ) const
{
U32 num_periods = mRecordingPeriods.size();
offset = llclamp(offset, 0u, num_periods - 1);
return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
}
void PeriodicRecording::handleStart()
{
getCurRecording().start();
}
void PeriodicRecording::handleStop()
{
getCurRecording().pause();
}
void PeriodicRecording::handleReset()
{
if (mAutoResize)
{
mRecordingPeriods.clear();
mRecordingPeriods.push_back(Recording());
}
else
{
for (std::vector<Recording>::iterator it = mRecordingPeriods.begin(), end_it = mRecordingPeriods.end();
it != end_it;
++it)
{
it->reset();
}
}
mCurPeriod = 0;
getCurRecording().setPlayState(getPlayState());
}
void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
{
getCurRecording().splitTo(other.getCurRecording());
}
F64 PeriodicRecording::getPeriodMean( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
F64 mean = 0;
if (num_periods <= 0) { return mean; }
S32 total_sample_count = 0;
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
if (mRecordingPeriods[index].getDuration() > 0.f)
{
S32 period_sample_count = mRecordingPeriods[index].getSampleCount(stat);
mean += mRecordingPeriods[index].getMean(stat) * period_sample_count;
total_sample_count += period_sample_count;
}
}
if (total_sample_count)
{
mean = mean / total_sample_count;
}
return mean;
}
F64 PeriodicRecording::getPeriodMin( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
F64 min_val = std::numeric_limits<F64>::max();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat));
}
return min_val;
}
F64 PeriodicRecording::getPeriodMax( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
F64 max_val = std::numeric_limits<F64>::min();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat));
}
return max_val;
}
F64 PeriodicRecording::getPeriodMin( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
F64 min_val = std::numeric_limits<F64>::max();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat));
}
return min_val;
}
F64 PeriodicRecording::getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/)
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
F64 max_val = std::numeric_limits<F64>::min();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat));
}
return max_val;
}
F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
LLUnit<F64, LLUnits::Seconds> total_duration = 0.f;
F64 mean = 0;
if (num_periods <= 0) { return mean; }
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
if (mRecordingPeriods[index].getDuration() > 0.f)
{
LLUnit<F64, LLUnits::Seconds> recording_duration = mRecordingPeriods[index].getDuration();
mean += mRecordingPeriods[index].getMean(stat) * recording_duration.value();
total_duration += recording_duration;
}
}
if (total_duration.value())
{
mean = mean / total_duration;
}
return mean;
}
///////////////////////////////////////////////////////////////////////
// ExtendableRecording
///////////////////////////////////////////////////////////////////////
void ExtendableRecording::extend()
{
// stop recording to get latest data
mPotentialRecording.update();
// push the data back to accepted recording
mAcceptedRecording.appendRecording(mPotentialRecording);
// flush data, so we can start from scratch
mPotentialRecording.reset();
}
void ExtendableRecording::handleStart()
{
mPotentialRecording.start();
}
void ExtendableRecording::handleStop()
{
mPotentialRecording.pause();
}
void ExtendableRecording::handleReset()
{
mAcceptedRecording.reset();
mPotentialRecording.reset();
}
void ExtendableRecording::handleSplitTo(ExtendableRecording& other)
{
mPotentialRecording.splitTo(other.mPotentialRecording);
}
///////////////////////////////////////////////////////////////////////
// ExtendablePeriodicRecording
///////////////////////////////////////////////////////////////////////
ExtendablePeriodicRecording::ExtendablePeriodicRecording()
: mAcceptedRecording(0),
mPotentialRecording(0)
{}
void ExtendablePeriodicRecording::extend()
{
// push the data back to accepted recording
mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
// flush data, so we can start from scratch
mPotentialRecording.reset();
}
void ExtendablePeriodicRecording::handleStart()
{
mPotentialRecording.start();
}
void ExtendablePeriodicRecording::handleStop()
{
mPotentialRecording.pause();
}
void ExtendablePeriodicRecording::handleReset()
{
mAcceptedRecording.reset();
mPotentialRecording.reset();
}
void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other)
{
mPotentialRecording.splitTo(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:
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,531 @@
/**
* @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
};
void start();
void stop();
void pause();
void resume();
void restart();
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() = 0;
// stop active behavior
virtual void handleStop() = 0;
// clear accumulated state, can be called while started
virtual void handleReset() = 0;
EPlayState mPlayState;
};
template<typename DERIVED>
class LLStopWatchControlsMixin
: public LLStopWatchControlsMixinCommon
{
public:
typedef LLStopWatchControlsMixin<DERIVED> self_t;
virtual void splitTo(DERIVED& other)
{
EPlayState play_state = getPlayState();
stop();
other.reset();
handleSplitTo(other);
other.setPlayState(play_state);
}
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
{
struct RecordingBuffers : public LLRefCount
{
RecordingBuffers();
void handOffTo(RecordingBuffers& other);
void makePrimary();
bool isPrimary() const;
void append(const RecordingBuffers& other);
void merge(const RecordingBuffers& other);
void reset(RecordingBuffers* other = NULL);
void flush();
AccumulatorBuffer<CountAccumulator> mCounts;
AccumulatorBuffer<SampleAccumulator> mSamples;
AccumulatorBuffer<EventAccumulator> mEvents;
AccumulatorBuffer<TimeBlockAccumulator> mStackTimers;
AccumulatorBuffer<MemStatAccumulator> mMemStats;
};
class Recording
: public LLStopWatchControlsMixin<Recording>
{
public:
Recording();
Recording(const Recording& other);
~Recording();
Recording& operator = (const Recording& other);
// 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();
// ensure that buffers are exclusively owned by this recording
void makeUnique() { mBuffers.makeUnique(); }
// Timer accessors
LLUnit<F64, LLUnits::Seconds> getSum(const TraceType<TimeBlockAccumulator>& stat);
LLUnit<F64, LLUnits::Seconds> getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat);
U32 getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat);
LLUnit<F64, LLUnits::Seconds> getPerSec(const TraceType<TimeBlockAccumulator>& stat);
LLUnit<F64, LLUnits::Seconds> getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat);
F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat);
// Memory accessors
LLUnit<F64, LLUnits::Bytes> getMin(const TraceType<MemStatAccumulator>& stat);
LLUnit<F64, LLUnits::Bytes> getMean(const TraceType<MemStatAccumulator>& stat);
LLUnit<F64, LLUnits::Bytes> getMax(const TraceType<MemStatAccumulator>& stat);
LLUnit<F64, LLUnits::Bytes> getStandardDeviation(const TraceType<MemStatAccumulator>& stat);
LLUnit<F64, LLUnits::Bytes> getLastValue(const TraceType<MemStatAccumulator>& stat);
LLUnit<F64, LLUnits::Bytes> getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
LLUnit<F64, LLUnits::Bytes> getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
LLUnit<F64, LLUnits::Bytes> getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
LLUnit<F64, LLUnits::Bytes> getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
LLUnit<F64, LLUnits::Bytes> getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
U32 getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat);
U32 getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat);
// CountStatHandle accessors
F64 getSum(const TraceType<CountAccumulator>& stat);
template <typename T>
T getSum(const CountStatHandle<T>& stat)
{
return (T)getSum(static_cast<const TraceType<CountAccumulator>&> (stat));
}
F64 getPerSec(const TraceType<CountAccumulator>& stat);
template <typename T>
T getPerSec(const CountStatHandle<T>& stat)
{
return (T)getPerSec(static_cast<const TraceType<CountAccumulator>&> (stat));
}
U32 getSampleCount(const TraceType<CountAccumulator>& stat);
// SampleStatHandle accessors
F64 getMin(const TraceType<SampleAccumulator>& stat);
template <typename T>
T getMin(const SampleStatHandle<T>& stat)
{
return (T)getMin(static_cast<const TraceType<SampleAccumulator>&> (stat));
}
F64 getMean(const TraceType<SampleAccumulator>& stat);
template <typename T>
T getMean(SampleStatHandle<T>& stat)
{
return (T)getMean(static_cast<const TraceType<SampleAccumulator>&> (stat));
}
F64 getMax(const TraceType<SampleAccumulator>& stat);
template <typename T>
T getMax(const SampleStatHandle<T>& stat)
{
return (T)getMax(static_cast<const TraceType<SampleAccumulator>&> (stat));
}
F64 getStandardDeviation(const TraceType<SampleAccumulator>& stat);
template <typename T>
T getStandardDeviation(const SampleStatHandle<T>& stat)
{
return (T)getStandardDeviation(static_cast<const TraceType<SampleAccumulator>&> (stat));
}
F64 getLastValue(const TraceType<SampleAccumulator>& stat);
template <typename T>
T getLastValue(const SampleStatHandle<T>& stat)
{
return (T)getLastValue(static_cast<const TraceType<SampleAccumulator>&> (stat));
}
U32 getSampleCount(const TraceType<SampleAccumulator>& stat);
// EventStatHandle accessors
F64 getSum(const TraceType<EventAccumulator>& stat);
template <typename T>
T getSum(const EventStatHandle<T>& stat)
{
return (T)getSum(static_cast<const TraceType<EventAccumulator>&> (stat));
}
F64 getMin(const TraceType<EventAccumulator>& stat);
template <typename T>
T getMin(const EventStatHandle<T>& stat)
{
return (T)getMin(static_cast<const TraceType<EventAccumulator>&> (stat));
}
F64 getMax(const TraceType<EventAccumulator>& stat);
template <typename T>
T getMax(const EventStatHandle<T>& stat)
{
return (T)getMax(static_cast<const TraceType<EventAccumulator>&> (stat));
}
F64 getMean(const TraceType<EventAccumulator>& stat);
template <typename T>
T getMean(EventStatHandle<T>& stat)
{
return (T)getMean(static_cast<const TraceType<EventAccumulator>&> (stat));
}
F64 getStandardDeviation(const TraceType<EventAccumulator>& stat);
template <typename T>
T getStandardDeviation(const EventStatHandle<T>& stat)
{
return (T)getStandardDeviation(static_cast<const TraceType<EventAccumulator>&> (stat));
}
F64 getLastValue(const TraceType<EventAccumulator>& stat);
template <typename T>
T getLastValue(const EventStatHandle<T>& stat)
{
return (T)getLastValue(static_cast<const TraceType<EventAccumulator>&> (stat));
}
U32 getSampleCount(const TraceType<EventAccumulator>& stat);
LLUnit<F64, LLUnits::Seconds> getDuration() const { return mElapsedSeconds; }
protected:
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;
LLUnit<F64, LLUnits::Seconds> mElapsedSeconds;
LLCopyOnWritePointer<RecordingBuffers> mBuffers;
};
class LL_COMMON_API PeriodicRecording
: public LLStopWatchControlsMixin<PeriodicRecording>
{
public:
PeriodicRecording(U32 num_periods, EPlayState state = STOPPED);
void nextPeriod();
size_t getNumRecordedPeriods() { return mNumPeriods; }
LLUnit<F64, LLUnits::Seconds> getDuration() const;
void appendPeriodicRecording(PeriodicRecording& other);
void appendRecording(Recording& recording);
Recording& getLastRecording();
const Recording& getLastRecording() const;
Recording& getCurRecording();
const Recording& getCurRecording() const;
Recording& getPrevRecording(U32 offset);
const Recording& getPrevRecording(U32 offset) const;
Recording snapshotCurRecording() const;
// catch all for stats that have a defined sum
template <typename T>
typename T::value_t getPeriodMin(const TraceType<T>& stat, size_t num_periods = U32_MAX)
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
typename T::value_t min_val = std::numeric_limits<typename T::value_t>::max();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
min_val = llmin(min_val, mRecordingPeriods[index].getSum(stat));
}
return min_val;
}
F64 getPeriodMin(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX);
template<typename T>
T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX)
{
return T(getPeriodMin(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods));
}
F64 getPeriodMin(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX);
template<typename T>
T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX)
{
return T(getPeriodMin(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods));
}
template <typename T>
F64 getPeriodMinPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
F64 min_val = std::numeric_limits<F64>::max();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
min_val = llmin(min_val, mRecordingPeriods[index].getPerSec(stat));
}
return min_val;
}
// catch all for stats that have a defined sum
template <typename T>
typename T::value_t getPeriodMax(const TraceType<T>& stat, size_t num_periods = U32_MAX)
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
typename T::value_t max_val = std::numeric_limits<typename T::value_t>::min();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
max_val = llmax(max_val, mRecordingPeriods[index].getSum(stat));
}
return max_val;
}
F64 getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX);
template<typename T>
T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX)
{
return T(getPeriodMax(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods));
}
F64 getPeriodMax(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX);
template<typename T>
T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX)
{
return T(getPeriodMax(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods));
}
template <typename T>
F64 getPeriodMaxPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
F64 max_val = std::numeric_limits<F64>::min();
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
max_val = llmax(max_val, mRecordingPeriods[index].getPerSec(stat));
}
return max_val;
}
// catch all for stats that have a defined sum
template <typename T>
typename T::mean_t getPeriodMean(const TraceType<T >& stat, size_t num_periods = U32_MAX)
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
typename T::mean_t mean = 0;
if (num_periods <= 0) { return mean; }
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
if (mRecordingPeriods[index].getDuration() > 0.f)
{
mean += mRecordingPeriods[index].getSum(stat);
}
}
mean = mean / num_periods;
return mean;
}
F64 getPeriodMean(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX);
template<typename T>
T getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX)
{
return T(getPeriodMean(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods));
}
F64 getPeriodMean(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX);
template<typename T>
T getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX)
{
return T(getPeriodMean(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods));
}
template <typename T>
typename T::mean_t getPeriodMeanPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)
{
size_t total_periods = mRecordingPeriods.size();
num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods);
typename T::mean_t mean = 0;
if (num_periods <= 0) { return mean; }
for (S32 i = 1; i <= num_periods; i++)
{
S32 index = (mCurPeriod + total_periods - i) % total_periods;
if (mRecordingPeriods[index].getDuration() > 0.f)
{
mean += mRecordingPeriods[index].getPerSec(stat);
}
}
mean = mean / num_periods;
return mean;
}
private:
// implementation for LLStopWatchControlsMixin
/*virtual*/ void handleStart();
/*virtual*/ void handleStop();
/*virtual*/ void handleReset();
/*virtual*/ void handleSplitTo(PeriodicRecording& other);
private:
std::vector<Recording> mRecordingPeriods;
const bool mAutoResize;
size_t mCurPeriod;
size_t mNumPeriods;
};
PeriodicRecording& get_frame_recording();
class ExtendableRecording
: public LLStopWatchControlsMixin<ExtendableRecording>
{
public:
void extend();
Recording& getAcceptedRecording() { return mAcceptedRecording; }
const Recording& getAcceptedRecording() const {return mAcceptedRecording;}
Recording& getPotentialRecording() { return mPotentialRecording; }
const Recording& getPotentialRecording() const { return mPotentialRecording;}
private:
// implementation for LLStopWatchControlsMixin
/*virtual*/ void handleStart();
/*virtual*/ void handleStop();
/*virtual*/ void handleReset();
/*virtual*/ void handleSplitTo(ExtendableRecording& other);
private:
Recording mAcceptedRecording;
Recording mPotentialRecording;
};
class ExtendablePeriodicRecording
: public LLStopWatchControlsMixin<ExtendablePeriodicRecording>
{
public:
ExtendablePeriodicRecording();
void extend();
PeriodicRecording& getAcceptedRecording() { return mAcceptedRecording; }
const PeriodicRecording& getAcceptedRecording() const {return mAcceptedRecording;}
PeriodicRecording& getPotentialRecording() { return mPotentialRecording; }
const PeriodicRecording& getPotentialRecording() const {return mPotentialRecording;}
private:
// implementation for LLStopWatchControlsMixin
/*virtual*/ void handleStart();
/*virtual*/ void handleStop();
/*virtual*/ void handleReset();
/*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other);
private:
PeriodicRecording mAcceptedRecording;
PeriodicRecording mPotentialRecording;
};
}
#endif // LL_LLTRACERECORDING_H

View File

@ -0,0 +1,292 @@
/**
* @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;
if (!mActiveRecordings.empty())
{
std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer());
mActiveRecordings.clear();
}
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.back()->mPartialRecording.handOffTo(active_recording->mPartialRecording);
}
mActiveRecordings.push_back(active_recording);
mActiveRecordings.back()->mPartialRecording.makePrimary();
}
ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( Recording* recording )
{
if (mActiveRecordings.empty()) return mActiveRecordings.rend();
mActiveRecordings.back()->mPartialRecording.flush();
TimeBlock::updateTimes();
active_recording_list_t::reverse_iterator it, end_it;
for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend();
it != end_it;
++it)
{
ActiveRecording* cur_recording = *it;
active_recording_list_t::reverse_iterator next_it = it;
++next_it;
// if we have another recording further down in the stack...
if (next_it != mActiveRecordings.rend())
{
// ...push our gathered data down to it
(*next_it)->mPartialRecording.append(cur_recording->mPartialRecording);
}
// copy accumulated measurements into result buffer and clear accumulator (mPartialRecording)
cur_recording->movePartialToTarget();
if (cur_recording->mTargetRecording == recording)
{
// found the recording, so return it
break;
}
}
if (it == end_it)
{
llwarns << "Recording not active on this thread" << llendl;
}
return it;
}
void ThreadRecorder::deactivate( Recording* recording )
{
active_recording_list_t::reverse_iterator it = bringUpToDate(recording);
if (it != mActiveRecordings.rend())
{
// and if we've found the recording we wanted to update
active_recording_list_t::reverse_iterator next_it = it;
++next_it;
if (next_it != mActiveRecordings.rend())
{
(*next_it)->mPartialRecording.makePrimary();
}
active_recording_list_t::iterator recording_to_remove = (++it).base();
llassert((*recording_to_remove)->mTargetRecording == recording);
delete *recording_to_remove;
mActiveRecordings.erase(recording_to_remove);
}
}
ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target )
: mTargetRecording(target)
{
}
void ThreadRecorder::ActiveRecording::movePartialToTarget()
{
mTargetRecording->mBuffers.write()->append(mPartialRecording);
// reset based on self to keep history
mPartialRecording.reset(&mPartialRecording);
}
///////////////////////////////////////////////////////////////////////
// SlaveThreadRecorder
///////////////////////////////////////////////////////////////////////
SlaveThreadRecorder::SlaveThreadRecorder(MasterThreadRecorder& master)
: mMasterRecorder(master)
{
mMasterRecorder.addSlaveThread(this);
}
SlaveThreadRecorder::~SlaveThreadRecorder()
{
mMasterRecorder.removeSlaveThread(this);
}
void SlaveThreadRecorder::pushToMaster()
{
mThreadRecording.stop();
{
LLMutexLock(mMasterRecorder.getSlaveListMutex());
mSharedData.appendFrom(mThreadRecording);
}
mThreadRecording.start();
}
void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source )
{
LLMutexLock lock(&mRecordingMutex);
appendRecording(source);
}
void SlaveThreadRecorder::SharedData::appendTo( Recording& sink )
{
LLMutexLock lock(&mRecordingMutex);
sink.appendRecording(*this);
}
void SlaveThreadRecorder::SharedData::mergeFrom( const RecordingBuffers& source )
{
LLMutexLock lock(&mRecordingMutex);
mBuffers.write()->merge(source);
}
void SlaveThreadRecorder::SharedData::mergeTo( RecordingBuffers& sink )
{
LLMutexLock lock(&mRecordingMutex);
sink.merge(*mBuffers);
}
void SlaveThreadRecorder::SharedData::reset()
{
LLMutexLock lock(&mRecordingMutex);
Recording::reset();
}
///////////////////////////////////////////////////////////////////////
// MasterThreadRecorder
///////////////////////////////////////////////////////////////////////
static 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.back()->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,126 @@
/**
* @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::vector<ActiveRecording*> active_recording_list_t;
public:
ThreadRecorder();
virtual ~ThreadRecorder();
void activate(Recording* recording);
void deactivate(Recording* recording);
active_recording_list_t::reverse_iterator bringUpToDate(Recording* recording);
virtual void pushToMaster() = 0;
TimeBlockTreeNode* getTimeBlockTreeNode(S32 index);
protected:
struct ActiveRecording
{
ActiveRecording(Recording* target);
Recording* mTargetRecording;
RecordingBuffers mPartialRecording;
void movePartialToTarget();
};
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; // list of slave thread recorders associated with this master
LLMutex mSlaveListMutex; // protects access to slave list
};
class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder
{
public:
SlaveThreadRecorder(MasterThreadRecorder& master);
~SlaveThreadRecorder();
// call this periodically to gather stats data for master thread to consume
/*virtual*/ void pushToMaster();
MasterThreadRecorder* mMaster;
class SharedData : public Recording
{
public:
void appendFrom(const Recording& source);
void appendTo(Recording& sink);
void mergeFrom(const RecordingBuffers& source);
void mergeTo(RecordingBuffers& sink);
void reset();
private:
LLMutex mRecordingMutex;
};
SharedData mSharedData;
MasterThreadRecorder& mMasterRecorder;
};
}
#endif // LL_LLTRACETHREADRECORDER_H

View File

@ -1,117 +0,0 @@
/**
* @file lltypeinfolookup.h
* @author Nat Goodspeed
* @date 2012-04-08
* @brief Template data structure like std::map<std::type_info*, T>
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Copyright (c) 2012, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLTYPEINFOLOOKUP_H)
#define LL_LLTYPEINFOLOOKUP_H
#include <boost/unordered_map.hpp>
#include <boost/functional/hash.hpp>
#include <boost/optional.hpp>
#include <functional> // std::binary_function
#include <typeinfo>
/**
* The following helper classes are based on the Boost.Unordered documentation:
* http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html
*/
/**
* Compute hash for a string passed as const char*
*/
struct const_char_star_hash: public std::unary_function<const char*, std::size_t>
{
std::size_t operator()(const char* str) const
{
std::size_t seed = 0;
for ( ; *str; ++str)
{
boost::hash_combine(seed, *str);
}
return seed;
}
};
/**
* Compute equality for strings passed as const char*
*
* I (nat) suspect that this is where the default behavior breaks for the
* const char* values returned from std::type_info::name(). If you compare the
* two const char* pointer values, as a naive, unspecialized implementation
* will surely do, they'll compare unequal.
*/
struct const_char_star_equal: public std::binary_function<const char*, const char*, bool>
{
bool operator()(const char* lhs, const char* rhs) const
{
return strcmp(lhs, rhs) == 0;
}
};
/**
* LLTypeInfoLookup is specifically designed for use cases for which you might
* consider std::map<std::type_info*, VALUE>. We have several such data
* structures in the viewer. The trouble with them is that at least on Linux,
* you can't rely on always getting the same std::type_info* for a given type:
* different load modules will produce different std::type_info*.
* LLTypeInfoLookup contains a workaround to address this issue.
*
* The API deliberately diverges from std::map in several respects:
* * It avoids iterators, not only begin()/end() but also as return values
* from insert() and find(). This bypasses transform_iterator overhead.
* * Since we literally use compile-time types as keys, the essential insert()
* and find() methods accept the key type as a @em template parameter,
* accepting and returning value_type as a normal runtime value. This is to
* permit future optimization (e.g. compile-time type hashing) without
* changing the API.
*/
template <typename VALUE>
class LLTypeInfoLookup
{
// Use this for our underlying implementation: lookup by
// std::type_info::name() string. This is one of the rare cases in which I
// dare use const char* directly, rather than std::string, because I'm
// sure that every value returned by std::type_info::name() is static.
// HOWEVER, specify our own hash + equality functors: naively comparing
// distinct const char* values won't work.
typedef boost::unordered_map<const char*, VALUE,
const_char_star_hash, const_char_star_equal> impl_map_type;
public:
typedef VALUE value_type;
LLTypeInfoLookup() {}
bool empty() const { return mMap.empty(); }
std::size_t size() const { return mMap.size(); }
template <typename KEY>
bool insert(const value_type& value)
{
// Obtain and store the std::type_info::name() string as the key.
// Return just the bool from std::map::insert()'s return pair.
return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second;
}
template <typename KEY>
boost::optional<value_type> find() const
{
// Use the std::type_info::name() string as the key.
typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name());
if (found == mMap.end())
return boost::optional<value_type>();
return found->second;
}
private:
impl_map_type mMap;
};
#endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */

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

@ -0,0 +1,563 @@
/**
* @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"
#include <boost/type_traits/is_same.hpp>
template<typename STORAGE_TYPE, typename UNIT_TYPE>
struct LLUnit
{
typedef LLUnit<STORAGE_TYPE, UNIT_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_STORAGE, typename OTHER_UNIT>
LLUnit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
: mValue(convert(other).mValue)
{}
bool operator == (const self_t& other)
{
return mValue = other.mValue;
}
// value assignment
self_t& operator = (storage_t value)
{
mValue = value;
return *this;
}
// unit assignment
template<typename OTHER_STORAGE, typename OTHER_UNIT>
self_t& operator = (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
{
mValue = convert(other).mValue;
return *this;
}
storage_t value() const
{
return mValue;
}
template<typename NEW_UNIT_TYPE>
STORAGE_TYPE getAs()
{
return LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(*this).value();
}
template<typename NEW_UNIT_TYPE>
STORAGE_TYPE setAs(STORAGE_TYPE val)
{
*this = LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(val);
}
void operator += (storage_t value)
{
mValue += value;
}
template<typename OTHER_STORAGE, typename OTHER_UNIT>
void operator += (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
{
mValue += convert(other).mValue;
}
void operator -= (storage_t value)
{
mValue -= value;
}
template<typename OTHER_STORAGE, typename OTHER_UNIT>
void operator -= (LLUnit<OTHER_STORAGE, OTHER_UNIT> other)
{
mValue -= convert(other).mValue;
}
void operator *= (storage_t multiplicand)
{
mValue *= multiplicand;
}
template<typename OTHER_UNIT, typename OTHER_STORAGE>
void operator *= (LLUnit<OTHER_STORAGE, OTHER_UNIT> multiplicand)
{
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
LL_BAD_TEMPLATE_INSTANTIATION(OTHER_UNIT, "Multiplication of unit types not supported.");
}
void operator /= (storage_t divisor)
{
mValue /= divisor;
}
template<typename OTHER_UNIT, typename OTHER_STORAGE>
void operator /= (LLUnit<OTHER_STORAGE, OTHER_UNIT> divisor)
{
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
LL_BAD_TEMPLATE_INSTANTIATION(OTHER_UNIT, "Illegal in-place division of unit types.");
}
template<typename SOURCE_STORAGE, typename SOURCE_UNITS>
static self_t convert(LLUnit<SOURCE_STORAGE, SOURCE_UNITS> v)
{
self_t result;
ll_convert_units(v, result);
return result;
}
protected:
storage_t mValue;
};
template<typename STORAGE_TYPE, typename UNIT_TYPE>
struct LLUnitImplicit : public LLUnit<STORAGE_TYPE, UNIT_TYPE>
{
typedef LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> self_t;
typedef typename LLUnit<STORAGE_TYPE, UNIT_TYPE>::storage_t storage_t;
typedef LLUnit<STORAGE_TYPE, UNIT_TYPE> base_t;
LLUnitImplicit(storage_t value = storage_t())
: base_t(value)
{}
template<typename OTHER_STORAGE, typename OTHER_UNIT>
LLUnitImplicit(LLUnit<OTHER_STORAGE, OTHER_UNIT> 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();
}
};
template<typename S1, typename T1, typename S2, typename T2>
LL_FORCE_INLINE void ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out, ...)
{
typedef boost::integral_constant<bool,
boost::is_same<T1, T2>::value
|| !boost::is_same<T1, typename T1::base_unit_t>::value
|| !boost::is_same<T2, typename T2::base_unit_t>::value> conversion_valid_t;
LL_STATIC_ASSERT(conversion_valid_t::value, "invalid conversion");
if (boost::is_same<T1, typename T1::base_unit_t>::value)
{
if (boost::is_same<T2, typename T2::base_unit_t>::value)
{
// T1 and T2 fully reduced and equal...just copy
out = (S2)in.value();
}
else
{
// reduce T2
LLUnit<S2, typename T2::base_unit_t> new_out;
ll_convert_units(in, new_out);
ll_convert_units(new_out, out);
}
}
else
{
// reduce T1
LLUnit<S1, typename T1::base_unit_t> new_in;
ll_convert_units(in, new_in);
ll_convert_units(new_in, out);
}
}
//
// operator +
//
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)
{
LLUnit<STORAGE_TYPE1, UNIT_TYPE1> result(first);
result += second;
return result;
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first);
result += second;
return result;
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second)
{
LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first);
result += second;
return result;
}
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)
{
LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> result(first);
result += second;
return result;
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator + (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> result(first);
result += second;
return result;
}
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second)
{
LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> result(first);
result += second;
return result;
}
//
// operator -
//
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator - (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)
{
LLUnit<STORAGE_TYPE1, UNIT_TYPE1> result(first);
result -= second;
return result;
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first);
result -= second;
return result;
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second)
{
LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first);
result -= second;
return result;
}
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second)
{
LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> result(first);
result -= second;
return result;
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator - (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> result(first);
result -= second;
return result;
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator - (SCALAR_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second)
{
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> result(first);
result -= second;
return result;
}
//
// operator *
//
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnit<STORAGE_TYPE, UNIT_TYPE> operator * (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second)
{
return LLUnit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first * second.value()));
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnit<STORAGE_TYPE, UNIT_TYPE> operator * (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
return LLUnit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first.value() * second));
}
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnit<STORAGE_TYPE2, UNIT_TYPE2>)
{
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "Multiplication of unit types results in new unit type - not supported.");
return LLUnit<STORAGE_TYPE1, UNIT_TYPE1>();
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator * (SCALAR_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second)
{
return LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>(first * second.value());
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator * (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
return LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>(first.value() * second);
}
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2>)
{
// spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "Multiplication of unit types results in new unit type - not supported.");
return LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>();
}
//
// operator /
//
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second)
{
return SCALAR_TYPE(first / second.value());
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnit<STORAGE_TYPE, UNIT_TYPE> operator / (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
return LLUnit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first.value() / second));
}
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
STORAGE_TYPE1 operator / (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second)
{
return STORAGE_TYPE1(first.value() / first.convert(second));
}
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE>
LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator / (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second)
{
return LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first.value() / second));
}
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2>
STORAGE_TYPE1 operator / (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second)
{
return STORAGE_TYPE1(first.value() / first.convert(second));
}
#define COMPARISON_OPERATORS(op) \
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> \
bool operator op (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) \
{ \
return first op second.value(); \
} \
\
template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> \
bool operator op (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) \
{ \
return first.value() op second; \
} \
\
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \
bool operator op (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) \
{ \
return first.value() op first.convert(second); \
} \
\
template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \
bool operator op (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) \
{ \
return first.value() op first.convert(second); \
}
COMPARISON_OPERATORS(<)
COMPARISON_OPERATORS(<=)
COMPARISON_OPERATORS(>)
COMPARISON_OPERATORS(>=)
COMPARISON_OPERATORS(==)
COMPARISON_OPERATORS(!=)
template<typename T>
struct LLGetUnitLabel
{
static const char* getUnitLabel() { return ""; }
};
template<typename T, typename STORAGE_T>
struct LLGetUnitLabel<LLUnit<STORAGE_T, T> >
{
static const char* getUnitLabel() { return T::getUnitLabel(); }
};
template<typename VALUE_TYPE>
struct LLUnitLinearOps
{
typedef LLUnitLinearOps<VALUE_TYPE> self_t;
LLUnitLinearOps(VALUE_TYPE val) : mValue (val) {}
operator VALUE_TYPE() const { return mValue; }
VALUE_TYPE mValue;
template<typename T>
self_t operator * (T other)
{
return mValue * other;
}
template<typename T>
self_t operator / (T other)
{
return mValue / other;
}
template<typename T>
self_t operator + (T other)
{
return mValue + other;
}
template<typename T>
self_t operator - (T other)
{
return mValue - other;
}
};
template<typename VALUE_TYPE>
struct LLUnitInverseLinearOps
{
typedef LLUnitInverseLinearOps<VALUE_TYPE> self_t;
LLUnitInverseLinearOps(VALUE_TYPE val) : mValue (val) {}
operator VALUE_TYPE() const { return mValue; }
VALUE_TYPE mValue;
template<typename T>
self_t operator * (T other)
{
return mValue / other;
}
template<typename T>
self_t operator / (T other)
{
return mValue * other;
}
template<typename T>
self_t operator + (T other)
{
return mValue - other;
}
template<typename T>
self_t operator - (T other)
{
return mValue + other;
}
};
#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \
struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }}
#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \
struct unit_name \
{ \
typedef base_unit_name base_unit_t; \
static const char* getUnitLabel() { return unit_label; } \
}; \
\
template<typename S1, typename S2> \
void ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out) \
{ \
out = (S2)(LLUnitLinearOps<S1>(in.value()) conversion_operation).mValue; \
} \
\
template<typename S1, typename S2> \
void ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out) \
{ \
out = (S2)(LLUnitInverseLinearOps<S1>(in.value()) conversion_operation).mValue; \
}
//
// Unit declarations
//
namespace LLUnits
{
LL_DECLARE_BASE_UNIT(Bytes, "B");
LL_DECLARE_DERIVED_UNIT(Kilobytes, "KB", Bytes, * 1000);
LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Kilobytes, * 1000);
LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Megabytes, * 1000);
LL_DECLARE_DERIVED_UNIT(Kibibytes, "KiB", Bytes, * 1024);
LL_DECLARE_DERIVED_UNIT(Mibibytes, "MiB", Kibibytes, * 1024);
LL_DECLARE_DERIVED_UNIT(Gibibytes, "GiB", Mibibytes, * 1024);
LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, / 8);
LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bytes, * 1000 / 8);
LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, * 1000 / 8);
LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, * 1000 / 8);
LL_DECLARE_DERIVED_UNIT(Kibibits, "Kib", Bytes, * 1024 / 8);
LL_DECLARE_DERIVED_UNIT(Mibibits, "Mib", Kibibits, * 1024 / 8);
LL_DECLARE_DERIVED_UNIT(Gibibits, "Gib", Mibibits, * 1024 / 8);
LL_DECLARE_BASE_UNIT(Seconds, "s");
LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, * 60);
LL_DECLARE_DERIVED_UNIT(Hours, "h", Seconds, * 60 * 60);
LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, / 1000);
LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, / 1000);
LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, / 1000);
LL_DECLARE_BASE_UNIT(Meters, "m");
LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, * 1000);
LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, / 100);
LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, / 1000);
LL_DECLARE_BASE_UNIT(Hertz, "Hz");
LL_DECLARE_DERIVED_UNIT(Kilohertz, "KHz", Hertz, * 1000);
LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Kilohertz, * 1000);
LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Megahertz, * 1000);
LL_DECLARE_BASE_UNIT(Radians, "rad");
LL_DECLARE_DERIVED_UNIT(Degrees, "deg", Radians, * 0.01745329251994);
} // namespace LLUnits
#endif // LL_LLUNIT_H

Some files were not shown because too many files have changed in this diff Show More