diff --git a/etc/message.xml b/etc/message.xml
index 8dfd75e13..690103bb7 100644
--- a/etc/message.xml
+++ b/etc/message.xml
@@ -670,19 +670,19 @@
EstateChangeInfo
true
- FetchInventoryDescendents
+ FetchInventoryDescendents2
false
WebFetchInventoryDescendents
false
- FetchInventory
+ FetchInventory2
true
- FetchLibDescendents
+ FetchLibDescendents2
true
- FetchLib
+ FetchLib2
true
diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index 288bf1ff5..36e3d99f1 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -195,15 +195,19 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
//-----------------------------------------------------------------------------
// updateMotions()
//-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation");
+static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim");
+
void LLCharacter::updateMotions(e_update_t update_type)
{
- LLFastTimer t(LLFastTimer::FTM_UPDATE_ANIMATION);
if (update_type == HIDDEN_UPDATE)
{
+ LLFastTimer t(FTM_UPDATE_HIDDEN_ANIMATION);
mMotionController.updateMotionsMinimal();
}
else
{
+ LLFastTimer t(FTM_UPDATE_ANIMATION);
// unpause if the number of outstanding pause requests has dropped to the initial one
if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1)
{
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 89db80b1c..60f21b25e 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -35,7 +35,7 @@ set(llcommon_SOURCE_FILES
llerrorthread.cpp
llevent.cpp
lleventtimer.cpp
- llfasttimer.cpp
+ llfasttimer_class.cpp
llfile.cpp
llfindlocale.cpp
llfixedbuffer.cpp
@@ -54,6 +54,7 @@ set(llcommon_SOURCE_FILES
llmetrics.cpp
llmortician.cpp
lloptioninterface.cpp
+ llptrto.cpp
llprocesslauncher.cpp
llprocessor.cpp
llqueuedthread.cpp
@@ -136,6 +137,7 @@ set(llcommon_HEADER_FILES
llextendedstatus.h
lleventtimer.h
llfasttimer.h
+ llfasttimer_class.h
llfile.h
llfindlocale.h
llfixedbuffer.h
@@ -171,6 +173,7 @@ set(llcommon_HEADER_FILES
llprocessor.h
llptrskiplist.h
llptrskipmap.h
+ llptrto.h
llqueuedthread.h
llrand.h
llrefcount.h
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
deleted file mode 100644
index f1d7eb305..000000000
--- a/indra/llcommon/llfasttimer.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * @file llfasttimer.cpp
- * @brief Implementation of the fast timer.
- *
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "linden_common.h"
-
-#include "llfasttimer.h"
-#include "llmemory.h"
-#include "llprocessor.h"
-
-#if LL_WINDOWS
-#define WIN32_LEAN_AND_MEAN
-#include
-#endif
-#include "lltimer.h"
-
-//////////////////////////////////////////////////////////////////////////////
-// statics
-
-LLFastTimer::EFastTimerType LLFastTimer::sCurType = LLFastTimer::FTM_OTHER;
-int LLFastTimer::sCurDepth = 0;
-U64 LLFastTimer::sStart[LLFastTimer::FTM_MAX_DEPTH];
-U64 LLFastTimer::sCounter[LLFastTimer::FTM_NUM_TYPES];
-U64 LLFastTimer::sCountHistory[LLFastTimer::FTM_HISTORY_NUM][LLFastTimer::FTM_NUM_TYPES];
-U64 LLFastTimer::sCountAverage[LLFastTimer::FTM_NUM_TYPES];
-U64 LLFastTimer::sCalls[LLFastTimer::FTM_NUM_TYPES];
-U64 LLFastTimer::sCallHistory[LLFastTimer::FTM_HISTORY_NUM][LLFastTimer::FTM_NUM_TYPES];
-U64 LLFastTimer::sCallAverage[LLFastTimer::FTM_NUM_TYPES];
-S32 LLFastTimer::sCurFrameIndex = -1;
-S32 LLFastTimer::sLastFrameIndex = -1;
-int LLFastTimer::sPauseHistory = 0;
-int LLFastTimer::sResetHistory = 0;
-
-U64 LLFastTimer::sClockResolution = calc_clock_frequency(50U); // Resolution of get_clock_count()
-
-U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
-{
- return sClockResolution >> 8;
-}
-
-void LLFastTimer::reset()
-{
- countsPerSecond(); // good place to calculate clock frequency
-
- if (sCurDepth != 0)
- {
- llerrs << "LLFastTimer::Reset() when sCurDepth != 0" << llendl;
- }
- if (sPauseHistory)
- {
- sResetHistory = 1;
- }
- else if (sResetHistory)
- {
- sCurFrameIndex = -1;
- sResetHistory = 0;
- }
- else if (sCurFrameIndex >= 0)
- {
- int hidx = sCurFrameIndex % FTM_HISTORY_NUM;
- for (S32 i=0; i> 8;
-}
-
-U64 LLFastTimer::getCPUClockCount64()
-{
- return get_clock_count();
-}
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 395ee8060..2b25f2fab 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -1,306 +1,35 @@
-/**
+/**
* @file llfasttimer.h
- * @brief Declaration of a fast timer.
+ * @brief Inline implementations of fast timers.
*
- * $LicenseInfo:firstyear=2004&license=viewergpl$
- *
- * Copyright (c) 2004-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * 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.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * 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.
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * 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_LLFASTTIMER_H
-#define LL_LLFASTTIMER_H
+#ifndef LL_FASTTIMER_H
+#define LL_FASTTIMER_H
-#define FAST_TIMER_ON 1
-
-
-class LL_COMMON_API LLFastTimer
-{
-public:
- enum EFastTimerType
- {
- // high level
- FTM_FRAME,
- FTM_UPDATE,
- FTM_RENDER,
- FTM_SWAP,
- FTM_CLIENT_COPY,
- FTM_IDLE,
- FTM_SLEEP,
-
- // general timers
- FT_STRING_FORMAT,
-
- // common messaging components
- FTM_PUMP,
- FTM_CURL,
- FTM_PUMPIO,
-
- // common simulation components
- FTM_UPDATE_ANIMATION,
- FTM_UPDATE_TERRAIN,
- FTM_UPDATE_PRIMITIVES,
- FTM_UPDATE_PARTICLES,
- FTM_SIMULATE_PARTICLES,
- FTM_UPDATE_SKY,
- FTM_UPDATE_TEXTURES,
- FTM_UPDATE_WLPARAM,
- FTM_UPDATE_WATER,
- FTM_UPDATE_CLOUDS,
- FTM_UPDATE_GRASS,
- FTM_UPDATE_TREE,
- FTM_UPDATE_AVATAR,
- FTM_UPDATE_RIGGED_VOLUME,
- FTM_SKIN_RIGGED,
- FTM_RIGGED_OCTREE,
-
- // common render components
- FTM_SHADOW_GEOMETRY,
- FTM_SHADOW_RENDER,
- FTM_SHADOW_TERRAIN,
- FTM_SHADOW_AVATAR,
- FTM_SHADOW_SIMPLE,
- FTM_SHADOW_ALPHA,
- FTM_SHADOW_TREE,
-
- FTM_RENDER_GEOMETRY,
- FTM_RENDER_TERRAIN,
- FTM_RENDER_SIMPLE,
- FTM_RENDER_FULLBRIGHT,
- FTM_RENDER_GLOW,
- FTM_RENDER_GRASS,
- FTM_RENDER_INVISIBLE,
- FTM_RENDER_SHINY,
- FTM_RENDER_BUMP,
- FTM_RENDER_TREES,
- FTM_RENDER_CHARACTERS,
- FTM_RENDER_OCCLUSION,
- FTM_RENDER_ALPHA,
- FTM_RENDER_CLOUDS,
- FTM_RENDER_HUD,
- FTM_RENDER_PARTICLES,
- FTM_RENDER_WATER,
- FTM_RENDER_WL_SKY,
- FTM_RENDER_FAKE_VBO_UPDATE,
- FTM_RENDER_TIMER,
- FTM_RENDER_UI,
- FTM_RENDER_BLOOM,
- FTM_RENDER_BLOOM_FBO,
- FTM_RENDER_FONTS,
-
- // deferred rendering
- FTM_RENDER_DEFERRED,
- FTM_BIND_DEFERRED,
- FTM_SUN_SHADOW,
- FTM_SOFTEN_SHADOW,
- FTM_EDGE_DETECTION,
- FTM_GI_TRACE,
- FTM_GI_GATHER,
- FTM_ATMOSPHERICS,
- FTM_LOCAL_LIGHTS,
- FTM_FULLSCREEN_LIGHTS,
- FTM_PROJECTORS,
- FTM_POST,
-
- FTM_VISIBLE_CLOUD,
-
- // newview specific
- FTM_MESSAGES,
- FTM_MOUSEHANDLER,
- FTM_KEYHANDLER,
- FTM_REBUILD,
- FTM_STATESORT,
- FTM_STATESORT_DRAWABLE,
- FTM_STATESORT_POSTSORT,
- FTM_MESH_UPDATE,
- FTM_MESH_LOCK1,
- FTM_MESH_LOCK2,
- FTM_LOAD_MESH_LOD,
- FTM_REBUILD_VBO,
- FTM_REBUILD_VOLUME_VB,
- FTM_FACE_GET_GEOM,
- FTM_FACE_GEOM_POSITION,
- FTM_FACE_GEOM_NORMAL,
- FTM_FACE_GEOM_TEXTURE,
- FTM_FACE_GEOM_COLOR,
- FTM_FACE_GEOM_EMISSIVE,
- FTM_FACE_GEOM_WEIGHTS,
- FTM_FACE_GEOM_BINORMAL,
- FTM_FACE_GEOM_INDEX,
- FTM_REBUILD_BRIDGE_VB,
- FTM_REBUILD_HUD_VB,
- FTM_REBUILD_TERRAIN_VB,
- FTM_REBUILD_WATER_VB,
- FTM_REBUILD_TREE_VB,
- FTM_REBUILD_PARTICLE_VB,
- FTM_REBUILD_CLOUD_VB,
- FTM_REBUILD_GRASS_VB,
- FTM_REBUILD_NONE_VB,
- FTM_REBUILD_OCCLUSION_VB,
- FTM_POOLS,
- FTM_POOLRENDER,
- FTM_IDLE_CB,
- FTM_WORLD_UPDATE,
- FTM_UPDATE_MOVE,
- FTM_OCTREE_BALANCE,
- FTM_UPDATE_LIGHTS,
- FTM_CULL,
- FTM_CULL_REBOUND,
- FTM_FRUSTUM_CULL,
- FTM_GEO_UPDATE,
- FTM_GEO_RESERVE,
- FTM_GEO_LIGHT,
- FTM_GEO_SHADOW,
- FTM_GEO_SKY,
- FTM_GEN_VOLUME,
- FTM_GEN_TRIANGLES,
- FTM_GEN_FLEX,
- FTM_AUDIO_UPDATE,
- FTM_RESET_DRAWORDER,
- FTM_OBJECTLIST_UPDATE,
- FTM_AVATAR_UPDATE,
- FTM_JOINT_UPDATE,
- FTM_ATTACHMENT_UPDATE,
- FTM_LOD_UPDATE,
- FTM_REGION_UPDATE,
- FTM_CLEANUP,
- FTM_NETWORK,
- FTM_IDLE_NETWORK,
- FTM_CREATE_OBJECT,
- FTM_LOAD_AVATAR,
- FTM_PROCESS_MESSAGES,
- FTM_PROCESS_OBJECTS,
- FTM_PROCESS_IMAGES,
- FTM_IMAGE_UPDATE,
- FTM_IMAGE_CREATE,
- FTM_IMAGE_DECODE,
- FTM_IMAGE_READBACK,
- FTM_IMAGE_MARK_DIRTY,
- FTM_PIPELINE,
- FTM_VFILE_WAIT,
- FTM_FLEXIBLE_UPDATE,
- FTM_OCCLUSION_READBACK,
- FTM_HUD_EFFECTS,
- FTM_HUD_UPDATE,
- FTM_INVENTORY,
- FTM_AUTO_SELECT,
- FTM_ARRANGE,
- FTM_FILTER,
- FTM_REFRESH,
- FTM_SORT,
- FTM_PICK,
- FTM_STATEMACHINE,
-
- // Temp
- FTM_TEMP1,
- FTM_TEMP2,
- FTM_TEMP3,
- FTM_TEMP4,
- FTM_TEMP5,
- FTM_TEMP6,
- FTM_TEMP7,
- FTM_TEMP8,
- FTM_TEMP9,
- FTM_TEMP10,
- FTM_TEMP11,
- FTM_TEMP12,
- FTM_TEMP13,
- FTM_TEMP14,
- FTM_TEMP15,
-
- FTM_OTHER, // Special, used by display code
-
- FTM_NUM_TYPES
- };
- enum { FTM_HISTORY_NUM = 60 };
- enum { FTM_MAX_DEPTH = 64 };
-
-public:
- static EFastTimerType sCurType;
-
- LLFastTimer(EFastTimerType type)
- {
-#if FAST_TIMER_ON
- mType = type;
- sCurType = type;
- // These don't get counted, because they use CPU clockticks
- //gTimerBins[gCurTimerBin]++;
- //LLTimer::sNumTimerCalls++;
-
- U64 cpu_clocks = getCPUClockCount32();
-
- sStart[sCurDepth] = cpu_clocks;
- sCurDepth++;
-#endif
- };
- ~LLFastTimer()
- {
-#if FAST_TIMER_ON
- U64 end,delta;
- int i;
-
- // These don't get counted, because they use CPU clockticks
- //gTimerBins[gCurTimerBin]++;
- //LLTimer::sNumTimerCalls++;
- end = getCPUClockCount32();
-
- sCurDepth--;
- delta = end - sStart[sCurDepth];
- sCounter[mType] += delta;
- sCalls[mType]++;
- // Subtract delta from parents
- for (i=0; i
+
+
+#if LL_WINDOWS
+#include "lltimer.h"
+#elif LL_LINUX || LL_SOLARIS
+#include
+#include
+#include "lltimer.h"
+#elif LL_DARWIN
+#include
+#include "lltimer.h" // get_clock_count()
+#else
+#error "architecture not supported"
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+// 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 LLFastTimer::sLogQueue;
+
+#define USE_RDTSC 0
+
+#if LL_LINUX || LL_SOLARIS
+U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
+#else
+U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
+#endif
+
+std::vector* LLFastTimer::sTimerInfos = NULL;
+U64 LLFastTimer::sTimerCycles = 0;
+U32 LLFastTimer::sTimerCalls = 0;
+
+
+// FIXME: move these declarations to the relevant modules
+
+// helper functions
+typedef LLTreeDFSPostIter timer_tree_bottom_up_iterator_t;
+
+static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& 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));
+}
+
+static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
+{
+ return timer_tree_bottom_up_iterator_t();
+}
+
+typedef LLTreeDFSIter timer_tree_dfs_iterator_t;
+
+
+static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& 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));
+}
+
+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
+{
+public:
+ NamedTimerFactory()
+ : mActiveTimerRoot(NULL),
+ mTimerRoot(NULL),
+ mAppTimer(NULL),
+ mRootFrameState(NULL)
+ {}
+
+ /*virtual */ void initSingleton()
+ {
+ mTimerRoot = new LLFastTimer::NamedTimer("root");
+
+ mActiveTimerRoot = new LLFastTimer::NamedTimer("Frame");
+ mActiveTimerRoot->setCollapsed(false);
+
+ mRootFrameState = new LLFastTimer::FrameState(mActiveTimerRoot);
+ mRootFrameState->mParent = &mTimerRoot->getFrameState();
+ mActiveTimerRoot->setParent(mTimerRoot);
+
+ mAppTimer = new LLFastTimer(mRootFrameState);
+ }
+
+ ~NamedTimerFactory()
+ {
+ std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer());
+
+ delete mAppTimer;
+ delete mActiveTimerRoot;
+ delete mTimerRoot;
+ delete mRootFrameState;
+ }
+
+ LLFastTimer::NamedTimer& createNamedTimer(const std::string& name)
+ {
+ timer_map_t::iterator found_it = mTimers.find(name);
+ if (found_it != mTimers.end())
+ {
+ return *found_it->second;
+ }
+
+ LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name);
+ 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* getActiveRootTimer() { return mActiveTimerRoot; }
+ LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; }
+ const LLFastTimer* getAppTimer() { return mAppTimer; }
+ LLFastTimer::FrameState& getRootFrameState() { return *mRootFrameState; }
+
+ typedef std::map 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* mActiveTimerRoot;
+ LLFastTimer::NamedTimer* mTimerRoot;
+ LLFastTimer* mAppTimer;
+ LLFastTimer::FrameState* mRootFrameState;
+};
+
+void update_cached_pointers_if_changed()
+{
+ // detect when elements have moved and update cached pointers
+ static LLFastTimer::FrameState* sFirstTimerAddress = NULL;
+ if (&*(LLFastTimer::getFrameStateList().begin()) != sFirstTimerAddress)
+ {
+ LLFastTimer::DeclareTimer::updateCachedPointers();
+ }
+ sFirstTimerAddress = &*(LLFastTimer::getFrameStateList().begin());
+}
+
+LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open )
+: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
+{
+ mTimer.setCollapsed(!open);
+ mFrameState = &mTimer.getFrameState();
+ update_cached_pointers_if_changed();
+}
+
+LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
+: mTimer(NamedTimerFactory::instance().createNamedTimer(name))
+{
+ mFrameState = &mTimer.getFrameState();
+ update_cached_pointers_if_changed();
+}
+
+// static
+void LLFastTimer::DeclareTimer::updateCachedPointers()
+{
+ // propagate frame state pointers to timer declarations
+ for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ {
+ // update cached pointer
+ it->mFrameState = &it->mTimer.getFrameState();
+ }
+
+ // also update frame states of timers on stack
+ LLFastTimer* cur_timerp = LLFastTimer::sCurTimerData.mCurTimer;
+ while(cur_timerp->mLastTimerData.mCurTimer != cur_timerp)
+ {
+ cur_timerp->mFrameState = &cur_timerp->mFrameState->mTimer->getFrameState();
+ cur_timerp = cur_timerp->mLastTimerData.mCurTimer;
+ }
+}
+
+//static
+#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
+U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
+{
+ return sClockResolution >> 8;
+}
+#else // windows or x86-mac or x86-linux or x86-solaris
+U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
+{
+#if 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
+#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())
+ // since that would change displayed MHz stats for CPUs
+ static bool firstcall = true;
+ static U64 sCPUClockFrequency;
+ if (firstcall)
+ {
+ QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency);
+ firstcall = false;
+ }
+#endif
+ return sCPUClockFrequency >> 8;
+}
+#endif
+
+LLFastTimer::FrameState::FrameState(LLFastTimer::NamedTimer* timerp)
+: mActiveCount(0),
+ mCalls(0),
+ mSelfTimeCounter(0),
+ mParent(NULL),
+ mLastCaller(NULL),
+ mMoveUpTree(false),
+ mTimer(timerp)
+{}
+
+
+LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
+: mName(name),
+ mCollapsed(true),
+ mParent(NULL),
+ mTotalTimeCounter(0),
+ mCountAverage(0),
+ mCallAverage(0),
+ mNeedsSorting(false)
+{
+ info_list_t& frame_state_list = getFrameStateList();
+ mFrameStateIndex = frame_state_list.size();
+ getFrameStateList().push_back(FrameState(this));
+
+ 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()
+{
+ delete[] mCountHistory;
+ delete[] mCallHistory;
+}
+
+std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
+{
+ F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond();
+ if (history_idx < 0)
+ {
+ // by default, show average number of call
+ return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getCountAverage() * ms_multiplier), (S32)getCallAverage());
+ }
+ else
+ {
+ return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx));
+ }
+}
+
+void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
+{
+ llassert_always(parent != this);
+ llassert_always(parent != NULL);
+
+ if (mParent)
+ {
+ // subtract our accumulated from previous parent
+ for (S32 i = 0; i < HISTORY_NUM; i++)
+ {
+ mParent->mCountHistory[i] -= mCountHistory[i];
+ }
+
+ // subtract average timing from previous parent
+ mParent->mCountAverage -= mCountAverage;
+
+ std::vector& children = mParent->getChildren();
+ std::vector::iterator found_it = std::find(children.begin(), children.end(), this);
+ if (found_it != children.end())
+ {
+ children.erase(found_it);
+ }
+ }
+
+ mParent = parent;
+ if (parent)
+ {
+ getFrameState().mParent = &parent->getFrameState();
+ parent->getChildren().push_back(this);
+ parent->mNeedsSorting = true;
+ }
+}
+
+S32 LLFastTimer::NamedTimer::getDepth()
+{
+ S32 depth = 0;
+ NamedTimer* timerp = mParent;
+ while(timerp)
+ {
+ depth++;
+ timerp = timerp->mParent;
+ }
+ return depth;
+}
+
+// static
+void LLFastTimer::NamedTimer::processTimes()
+{
+ if (sCurFrameIndex < 0) return;
+
+ buildHierarchy();
+ accumulateTimings();
+}
+
+// sort timer info structs by depth first traversal order
+struct SortTimersDFS
+{
+ bool operator()(const LLFastTimer::FrameState& i1, const LLFastTimer::FrameState& i2)
+ {
+ return i1.mTimer->getFrameStateIndex() < i2.mTimer->getFrameStateIndex();
+ }
+};
+
+// 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());
+ it != end_timer_tree_bottom_up();
+ ++it)
+ {
+ NamedTimer* timerp = *it;
+ // skip root timer
+ if (timerp == NamedTimerFactory::instance().getRootTimer()) continue;
+
+ if (timerp->getFrameState().mMoveUpTree)
+ {
+ // since ancestors have already been visited, reparenting won't affect tree traversal
+ //step up tree, bringing our descendants with us
+ //llinfos << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() <<
+ // " to child of " << timerp->getParent()->getParent()->getName() << llendl;
+ timerp->setParent(timerp->getParent()->getParent());
+ timerp->getFrameState().mMoveUpTree = false;
+
+ // don't bubble up any ancestors until descendants are done bubbling up
+ 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();
+
+ // 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->mLastTimerData.mCurTimer != cur_timer)
+ {
+ U32 cumulative_time_delta = cur_time - cur_timer->mStartTime;
+ U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime;
+ cur_data->mChildTime = 0;
+ cur_timer->mFrameState->mSelfTimeCounter += self_time_delta;
+ cur_timer->mStartTime = cur_time;
+
+ cur_data = &cur_timer->mLastTimerData;
+ cur_data->mChildTime += cumulative_time_delta;
+
+ cur_timer = cur_timer->mLastTimerData.mCurTimer;
+ }
+
+ // traverse tree in DFS post order, or bottom up
+ for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getActiveRootTimer());
+ it != end_timer_tree_bottom_up();
+ ++it)
+ {
+ NamedTimer* timerp = (*it);
+ timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter;
+ for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it)
+ {
+ timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter;
+ }
+
+ S32 cur_frame = sCurFrameIndex;
+ if (cur_frame >= 0)
+ {
+ // update timer history
+ int hidx = cur_frame % HISTORY_NUM;
+
+ timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter;
+ timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
+ timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
+ timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
+ }
+ }
+}
+
+// static
+void LLFastTimer::NamedTimer::resetFrame()
+{
+ if (sLog)
+ { //output current frame counts to performance log
+
+ static S32 call_count = 0;
+ if (call_count % 100 == 0)
+ {
+ llinfos << "countsPerSecond (32 bit): " << countsPerSecond() << llendl;
+ llinfos << "get_clock_count (64 bit): " << get_clock_count() << llendl;
+ llinfos << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << llendl;
+ llinfos << "getCPUClockCount32() " << getCPUClockCount32() << llendl;
+ llinfos << "getCPUClockCount64() " << getCPUClockCount64() << llendl;
+ llinfos << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << llendl;
+ }
+ call_count++;
+
+ F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
+
+ F64 total_time = 0;
+ LLSD sd;
+
+ {
+ for (instance_iter it = beginInstances(); it != endInstances(); ++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;
+
+ // 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;
+ }
+ }
+
+ sd["Total"]["Time"] = (LLSD::Real) total_time;
+ sd["Total"]["Calls"] = (LLSD::Integer) 1;
+
+ {
+ LLMutexLock lock(sLogLock);
+ sLogQueue.push(sd);
+ }
+ }
+
+
+ // tag timers by position in depth first traversal of tree
+ S32 index = 0;
+ for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
+ it != end_timer_tree();
+ ++it)
+ {
+ NamedTimer* timerp = (*it);
+
+ timerp->mFrameStateIndex = index;
+ index++;
+
+ llassert_always(timerp->mFrameStateIndex < (S32)getFrameStateList().size());
+ }
+
+ // sort timers by DFS traversal order to improve cache coherency
+ std::sort(getFrameStateList().begin(), getFrameStateList().end(), SortTimersDFS());
+
+ // update pointers into framestatelist now that we've sorted it
+ DeclareTimer::updateCachedPointers();
+
+ // 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();
+ }
+ }
+ }
+
+ //sTimerCycles = 0;
+ //sTimerCalls = 0;
+}
+
+//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->mLastTimerData.mCurTimer != cur_timer)
+ {
+ cur_timer->mStartTime = cur_time;
+ cur_data->mChildTime = 0;
+
+ cur_data = &cur_timer->mLastTimerData;
+ cur_timer = cur_data->mCurTimer;
+ }
+
+ // reset all history
+ {
+ for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ {
+ NamedTimer& timer = *it;
+ if (&timer != NamedTimerFactory::instance().getRootTimer())
+ {
+ timer.setParent(NamedTimerFactory::instance().getRootTimer());
+ }
+
+ timer.mCountAverage = 0;
+ timer.mCallAverage = 0;
+ memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
+ memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
+ }
+ }
+
+ sLastFrameIndex = 0;
+ sCurFrameIndex = 0;
+}
+
+//static
+LLFastTimer::info_list_t& LLFastTimer::getFrameStateList()
+{
+ if (!sTimerInfos)
+ {
+ sTimerInfos = new info_list_t();
+ }
+ return *sTimerInfos;
+}
+
+
+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
+{
+ llassert_always(mFrameStateIndex >= 0);
+ if (this == NamedTimerFactory::instance().getActiveRootTimer())
+ {
+ return NamedTimerFactory::instance().getRootFrameState();
+ }
+ return getFrameStateList()[mFrameStateIndex];
+}
+
+// static
+LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer()
+{
+ return *NamedTimerFactory::instance().getActiveRootTimer();
+}
+
+std::vector::const_iterator LLFastTimer::NamedTimer::beginChildren()
+{
+ return mChildren.begin();
+}
+
+std::vector::const_iterator LLFastTimer::NamedTimer::endChildren()
+{
+ return mChildren.end();
+}
+
+std::vector& LLFastTimer::NamedTimer::getChildren()
+{
+ return mChildren;
+}
+
+//static
+void LLFastTimer::nextFrame()
+{
+ countsPerSecond(); // good place to calculate clock frequency
+ U64 frame_time = getCPUClockCount64();
+ if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff)
+ {
+ llinfos << "Slow frame, fast timers inaccurate" << llendl;
+ }
+
+ if (!sPauseHistory)
+ {
+ NamedTimer::processTimes();
+ sLastFrameIndex = sCurFrameIndex++;
+ }
+
+ // get ready for next frame
+ NamedTimer::resetFrame();
+ sLastFrameTime = frame_time;
+}
+
+//static
+void LLFastTimer::dumpCurTimes()
+{
+ // accumulate timings, etc.
+ NamedTimer::processTimes();
+
+ F64 clock_freq = (F64)countsPerSecond();
+ F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds
+
+ // walk over timers in depth order and output timings
+ for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer());
+ it != end_timer_tree();
+ ++it)
+ {
+ NamedTimer* timerp = (*it);
+ F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
+ // Don't bother with really brief times, keep output concise
+ if (total_time_ms < 0.1) continue;
+
+ std::ostringstream out_str;
+ for (S32 i = 0; i < timerp->getDepth(); i++)
+ {
+ out_str << "\t";
+ }
+
+
+ out_str << timerp->getName() << " "
+ << std::setprecision(3) << total_time_ms << " ms, "
+ << timerp->getHistoricalCalls(0) << " calls";
+
+ llinfos << out_str.str() << llendl;
+ }
+}
+
+//static
+void LLFastTimer::reset()
+{
+ NamedTimer::reset();
+}
+
+
+//static
+void LLFastTimer::writeLog(std::ostream& os)
+{
+ while (!sLogQueue.empty())
+ {
+ LLSD& sd = sLogQueue.front();
+ LLSDSerialize::toXML(sd, os);
+ LLMutexLock lock(sLogLock);
+ sLogQueue.pop();
+ }
+}
+
+//static
+const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name)
+{
+ return NamedTimerFactory::instance().getTimerByName(name);
+}
+
+LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
+: mFrameState(state)
+{
+ U32 start_time = getCPUClockCount32();
+ mStartTime = start_time;
+ mFrameState->mActiveCount++;
+ LLFastTimer::sCurTimerData.mCurTimer = this;
+ LLFastTimer::sCurTimerData.mFrameState = mFrameState;
+ LLFastTimer::sCurTimerData.mChildTime = 0;
+ mLastTimerData = LLFastTimer::sCurTimerData;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Important note: These implementations must be FAST!
+//
+
+
+//LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp
+// These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures.
+U32 LLFastTimer::getCPUClockCount32()
+{
+ return (U32)(get_clock_count()>>8);
+}
+
+U64 LLFastTimer::getCPUClockCount64()
+{
+ return get_clock_count();
+}
+
+#if LL_WINDOWS
+std::string LLFastTimer::sClockType = "QueryPerformanceCounter";
+#else
+std::string LLFastTimer::sClockType = "gettimeofday";
+#endif
+
diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h
new file mode 100644
index 000000000..9e7fdaec6
--- /dev/null
+++ b/indra/llcommon/llfasttimer_class.h
@@ -0,0 +1,277 @@
+/**
+ * @file llfasttimer_class.h
+ * @brief Declaration of a fast timer.
+ *
+ * $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_FASTTIMER_CLASS_H
+#define LL_FASTTIMER_CLASS_H
+
+#include "llinstancetracker.h"
+
+#define FAST_TIMER_ON 1
+#define TIME_FAST_TIMERS 0
+#define DEBUG_FAST_TIMER_THREADS 1
+
+class LLMutex;
+
+#include
+#include "llsd.h"
+
+LL_COMMON_API void assert_main_thread();
+
+class LL_COMMON_API LLFastTimer
+{
+public:
+ class NamedTimer;
+
+ struct LL_COMMON_API FrameState
+ {
+ FrameState(NamedTimer* timerp);
+
+ 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
+ };
+
+ // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
+ class LL_COMMON_API NamedTimer
+ : public LLInstanceTracker
+ {
+ friend class DeclareTimer;
+ public:
+ ~NamedTimer();
+
+ 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::const_iterator child_const_iter;
+ child_const_iter beginChildren();
+ child_const_iter endChildren();
+ std::vector& 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();
+
+ S32 getFrameStateIndex() const { return mFrameStateIndex; }
+
+ 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
+ //
+ S32 mFrameStateIndex;
+
+ std::string mName;
+
+ U32 mTotalTimeCounter;
+
+ U32 mCountAverage;
+ U32 mCallAverage;
+
+ U32* mCountHistory;
+ U32* mCallHistory;
+
+ // tree structure
+ NamedTimer* mParent; // NamedTimer of caller(parent)
+ std::vector 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
+ {
+ friend class LLFastTimer;
+ public:
+ DeclareTimer(const std::string& name, bool open);
+ DeclareTimer(const std::string& name);
+
+ static void updateCachedPointers();
+
+ private:
+ NamedTimer& mTimer;
+ FrameState* mFrameState;
+ };
+
+public:
+ LLFastTimer(LLFastTimer::FrameState* state);
+
+ LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
+ : mFrameState(timer.mFrameState)
+ {
+#if TIME_FAST_TIMERS
+ U64 timer_start = getCPUClockCount64();
+#endif
+#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 TIME_FAST_TIMERS
+ U64 timer_end = getCPUClockCount64();
+ sTimerCycles += timer_end - timer_start;
+#endif
+#if DEBUG_FAST_TIMER_THREADS
+#if !LL_RELEASE
+ assert_main_thread();
+#endif
+#endif
+ }
+
+ LL_FORCE_INLINE ~LLFastTimer()
+ {
+#if TIME_FAST_TIMERS
+ U64 timer_start = getCPUClockCount64();
+#endif
+#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
+#if TIME_FAST_TIMERS
+ U64 timer_end = getCPUClockCount64();
+ sTimerCycles += timer_end - timer_start;
+ sTimerCalls++;
+#endif
+ }
+
+public:
+ static LLMutex* sLogLock;
+ static std::queue sLogQueue;
+ static BOOL sLog;
+ static BOOL sMetricLog;
+ static std::string sLogName;
+ static bool sPauseHistory;
+ static bool sResetHistory;
+ static U64 sTimerCycles;
+ static U32 sTimerCalls;
+
+ typedef std::vector info_list_t;
+ static info_list_t& getFrameStateList();
+
+
+ // call this once a frame to reset timers
+ static void nextFrame();
+
+ // 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;
+ static std::string sClockType;
+
+public:
+ static U32 getCPUClockCount32();
+ static U64 getCPUClockCount64();
+ static U64 sClockResolution;
+
+private:
+ static S32 sCurFrameIndex;
+ static S32 sLastFrameIndex;
+ static U64 sLastFrameTime;
+ static info_list_t* sTimerInfos;
+
+ U32 mStartTime;
+ LLFastTimer::FrameState* mFrameState;
+ LLFastTimer::CurTimerData mLastTimerData;
+
+};
+
+typedef class LLFastTimer LLFastTimer;
+
+#endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llptrto.cpp b/indra/llcommon/llptrto.cpp
new file mode 100644
index 000000000..b270291bd
--- /dev/null
+++ b/indra/llcommon/llptrto.cpp
@@ -0,0 +1,102 @@
+/**
+ * @file llptrto.cpp
+ * @author Nat Goodspeed
+ * @date 2008-08-20
+ * @brief Test for llptrto.h
+ *
+ * $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$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llptrto.h"
+// STL headers
+// std headers
+// external library headers
+#include
+#include
+// other Linden headers
+#include "llmemory.h"
+
+// a refcounted class
+class RCFoo: public LLRefCount
+{
+public:
+ RCFoo() {}
+};
+
+// a refcounted subclass
+class RCSubFoo: public RCFoo
+{
+public:
+ RCSubFoo() {}
+};
+
+// a refcounted class using the other refcount base class
+class TSRCFoo: public LLThreadSafeRefCount
+{
+public:
+ TSRCFoo() {}
+};
+
+// a non-refcounted class
+class Bar
+{
+public:
+ Bar() {}
+};
+
+// a non-refcounted subclass
+class SubBar: public Bar
+{
+public:
+ SubBar() {}
+};
+
+int main(int argc, char *argv[])
+{
+ // test LLPtrTo<>
+ BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, Bar*>::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, SubBar*>::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, int*>::value));
+
+ // Test LLRemovePointer<>. Note that we remove both pointer variants from
+ // each kind of type, regardless of whether the variant makes sense.
+ BOOST_STATIC_ASSERT((boost::is_same::type, RCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same >::type, RCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, RCSubFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same >::type, RCSubFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, TSRCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same >::type, TSRCFoo>::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, Bar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same >::type, Bar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, SubBar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same >::type, SubBar>::value));
+ BOOST_STATIC_ASSERT((boost::is_same::type, int>::value));
+ BOOST_STATIC_ASSERT((boost::is_same >::type, int>::value));
+
+ return 0;
+}
diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h
new file mode 100644
index 000000000..7091d36f6
--- /dev/null
+++ b/indra/llcommon/llptrto.h
@@ -0,0 +1,87 @@
+/**
+ * @file llptrto.h
+ * @author Nat Goodspeed
+ * @date 2008-08-19
+ * @brief LLPtrTo is a template helper to pick either TARGET* or -- when
+ * TARGET is a subclass of LLRefCount or LLThreadSafeRefCount --
+ * LLPointer. LLPtrTo<> chooses whichever pointer type is best.
+ *
+ * $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$
+ */
+
+#if ! defined(LL_LLPTRTO_H)
+#define LL_LLPTRTO_H
+
+#include "llpointer.h"
+#include "llrefcount.h" // LLRefCount
+#include "llthread.h" // LLThreadSafeRefCount
+#include
+#include
+#include
+
+/**
+ * LLPtrTo::type is either of two things:
+ *
+ * * When TARGET is a subclass of either LLRefCount or LLThreadSafeRefCount,
+ * LLPtrTo::type is LLPointer.
+ * * Otherwise, LLPtrTo::type is TARGET*.
+ *
+ * This way, a class template can use LLPtrTo::type to select an
+ * appropriate pointer type to store.
+ */
+template
+struct LLPtrTo
+{
+ typedef T* type;
+};
+
+/// specialize for subclasses of LLRefCount
+template
+struct LLPtrTo >::type>
+{
+ typedef LLPointer type;
+};
+
+/// specialize for subclasses of LLThreadSafeRefCount
+template
+struct LLPtrTo >::type>
+{
+ typedef LLPointer type;
+};
+
+/**
+ * LLRemovePointer::type gets you the underlying (pointee) type.
+ */
+template
+struct LLRemovePointer
+{
+ typedef typename boost::remove_pointer::type type;
+};
+
+/// specialize for LLPointer
+template
+struct LLRemovePointer< LLPointer >
+{
+ typedef SOMECLASS type;
+};
+
+#endif /* ! defined(LL_LLPTRTO_H) */
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 27bbf7e98..f9128b574 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -43,6 +43,9 @@
#include // for WideCharToMultiByte
#endif
+LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format");
+
+
std::string ll_safe_string(const char* in)
{
if(in) return std::string(in);
@@ -1196,7 +1199,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
template<>
S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
{
- LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT);
+ LLFastTimer ft(FT_STRING_FORMAT);
S32 res = 0;
std::string output;
@@ -1269,7 +1272,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions)
template<>
S32 LLStringUtil::format(std::string& s, const LLSD& substitutions)
{
- LLFastTimer ft(LLFastTimer::FT_STRING_FORMAT);
+ LLFastTimer ft(FT_STRING_FORMAT);
S32 res = 0;
if (!substitutions.isMap())
diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h
index 89ef7d616..9842f4da1 100644
--- a/indra/llmath/llmath.h
+++ b/indra/llmath/llmath.h
@@ -531,13 +531,13 @@ inline void ll_remove_outliers(std::vector& data, F32 k)
i++;
}
- S32 j = data.size()-1;
+ S32 j = (S32)data.size()-1;
while (j > 0 && data[j] > max)
{
j--;
}
- if (j < data.size()-1)
+ if (j < (S32)data.size()-1)
{
data.erase(data.begin()+j, data.end());
}
diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h
index 8b7df774e..1324b49df 100644
--- a/indra/llmath/v4coloru.h
+++ b/indra/llmath/v4coloru.h
@@ -57,8 +57,8 @@ public:
{
U8 mV[LENGTHOFCOLOR4U];
U32 mAll;
- LLColor4* mSources;
- LLColor4U* mSourcesU;
+ //LLColor4* mSources;
+ //LLColor4U* mSourcesU;
};
diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp
index 0560a319b..6d13e8f73 100644
--- a/indra/llmessage/llfiltersd2xmlrpc.cpp
+++ b/indra/llmessage/llfiltersd2xmlrpc.cpp
@@ -91,6 +91,8 @@
#include "llsdserialize.h"
#include "lluuid.h"
+#include "llfasttimer.h"
+
// spammy mode
//#define LL_SPEW_STREAM_OUT_DEBUGGING 1
@@ -314,6 +316,7 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse()
}
+static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response");
// virtual
LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
const LLChannelDescriptors& channels,
@@ -322,6 +325,8 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl(
LLSD& context,
LLPumpIO* pump)
{
+ LLFastTimer t(FTM_PROCESS_SD2XMLRPC_RESPONSE);
+
PUMP_DEBUG;
// This pipe does not work if it does not have everyting. This
// could be addressed by making a stream parser for llsd which
@@ -388,6 +393,8 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest()
{
}
+static LLFastTimer::DeclareTimer FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request");
+
// virtual
LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
const LLChannelDescriptors& channels,
@@ -396,6 +403,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl(
LLSD& context,
LLPumpIO* pump)
{
+ LLFastTimer t(FTM_PROCESS_SD2XMLRPC_REQUEST);
// This pipe does not work if it does not have everyting. This
// could be addressed by making a stream parser for llsd which
// handled partial information.
@@ -592,6 +600,8 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD()
{
}
+static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response");
+
LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
@@ -599,6 +609,8 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl(
LLSD& context,
LLPumpIO* pump)
{
+ LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_RESPONSE);
+
PUMP_DEBUG;
if(!eos) return STATUS_BREAK;
if(!buffer) return STATUS_ERROR;
@@ -674,6 +686,7 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD()
{
}
+static LLFastTimer::DeclareTimer FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request");
LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
@@ -681,6 +694,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl(
LLSD& context,
LLPumpIO* pump)
{
+ LLFastTimer t(FTM_PROCESS_XMLRPC2LLSD_REQUEST);
PUMP_DEBUG;
if(!eos) return STATUS_BREAK;
if(!buffer) return STATUS_ERROR;
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index a659027ad..eb9fd80b8 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -51,6 +51,7 @@
#include "llstat.h"
#include "llstl.h"
#include "lltimer.h"
+#include "llfasttimer.h"
#include
@@ -146,6 +147,7 @@ private:
LLSD mHeaders;
};
+static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PIPE("HTTP Pipe");
LLIOPipe::EStatus LLHTTPPipe::process_impl(
const LLChannelDescriptors& channels,
buffer_ptr_t& buffer,
@@ -153,6 +155,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
LLSD& context,
LLPumpIO* pump)
{
+ LLFastTimer t(FTM_PROCESS_HTTP_PIPE);
PUMP_DEBUG;
lldebugs << "LLSDHTTPServer::process_impl" << llendl;
@@ -434,6 +437,9 @@ protected:
/**
* LLHTTPResponseHeader
*/
+
+static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_HEADER("HTTP Header");
+
// virtual
LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
const LLChannelDescriptors& channels,
@@ -442,6 +448,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
LLSD& context,
LLPumpIO* pump)
{
+ LLFastTimer t(FTM_PROCESS_HTTP_HEADER);
PUMP_DEBUG;
LLMemType m1(LLMemType::MTYPE_IO_HTTP_SERVER);
if(eos)
@@ -636,6 +643,8 @@ void LLHTTPResponder::markBad(
<< "