summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt6
-rw-r--r--indra/llcommon/llallocator_heap_profile.cpp31
-rw-r--r--indra/llcommon/llapp.cpp2
-rw-r--r--indra/llcommon/llchat.h12
-rw-r--r--indra/llcommon/lldate.cpp3
-rw-r--r--indra/llcommon/lldictionary.h9
-rw-r--r--indra/llcommon/llerror.h2
-rw-r--r--indra/llcommon/llerrorlegacy.h8
-rw-r--r--indra/llcommon/lleventtimer.cpp95
-rw-r--r--indra/llcommon/lleventtimer.h60
-rw-r--r--indra/llcommon/llfasttimer.h340
-rw-r--r--indra/llcommon/llfasttimer_class.cpp768
-rw-r--r--indra/llcommon/llfasttimer_class.h272
-rw-r--r--indra/llcommon/llfoldertype.cpp5
-rw-r--r--indra/llcommon/llinstancetracker.cpp20
-rw-r--r--indra/llcommon/llinstancetracker.h69
-rw-r--r--indra/llcommon/lllivefile.cpp2
-rw-r--r--indra/llcommon/llpointer.h1
-rw-r--r--indra/llcommon/llpreprocessor.h15
-rw-r--r--indra/llcommon/llprocessor.cpp3
-rw-r--r--indra/llcommon/llrefcount.cpp11
-rw-r--r--indra/llcommon/llrefcount.h14
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp15
-rw-r--r--indra/llcommon/llstring.h1
-rw-r--r--indra/llcommon/lltimer.cpp51
-rw-r--r--indra/llcommon/lltimer.h21
-rw-r--r--indra/llcommon/lltreeiterators.h34
-rw-r--r--indra/llcommon/lluri.cpp15
-rw-r--r--indra/llcommon/llworkerthread.cpp1
-rw-r--r--indra/llcommon/tests/llinstancetracker_test.cpp28
30 files changed, 1491 insertions, 423 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index ac7cc2cdac..4481d334b2 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -50,7 +50,8 @@ set(llcommon_SOURCE_FILES
lleventdispatcher.cpp
lleventfilter.cpp
llevents.cpp
- llfasttimer.cpp
+ lleventtimer.cpp
+ llfasttimer_class.cpp
llfile.cpp
llfindlocale.cpp
llfixedbuffer.cpp
@@ -164,7 +165,6 @@ set(llcommon_HEADER_FILES
llhttpstatuscodes.h
llindexedqueue.h
llinstancetracker.h
- llinstancetracker.h
llkeythrottle.h
lllazy.h
lllistenerwrapper.h
@@ -250,7 +250,7 @@ list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
if(LLCOMMON_LINK_SHARED)
add_library (llcommon SHARED ${llcommon_SOURCE_FILES})
- ll_stage_sharedlib(llcommon)
+ ll_stage_sharedlib(llcommon)
else(LLCOMMON_LINK_SHARED)
add_library (llcommon ${llcommon_SOURCE_FILES})
endif(LLCOMMON_LINK_SHARED)
diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp
index 0a807702d0..e50d59fd4b 100644
--- a/indra/llcommon/llallocator_heap_profile.cpp
+++ b/indra/llcommon/llallocator_heap_profile.cpp
@@ -113,21 +113,24 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text)
++j;
while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens
- llassert_always(j != line_elems.end());
- ++j; // skip the '@'
-
- mLines.push_back(line(live_count, live_size, tot_count, tot_size));
- line & current_line = mLines.back();
-
- for(; j != line_elems.end(); ++j)
- {
- if(!j->empty()) {
- U32 marker = boost::lexical_cast<U32>(*j);
- current_line.mTrace.push_back(marker);
- }
- }
+ llassert(j != line_elems.end());
+ if (j != line_elems.end())
+ {
+ ++j; // skip the '@'
+
+ mLines.push_back(line(live_count, live_size, tot_count, tot_size));
+ line & current_line = mLines.back();
+
+ for(; j != line_elems.end(); ++j)
+ {
+ if(!j->empty())
+ {
+ U32 marker = boost::lexical_cast<U32>(*j);
+ current_line.mTrace.push_back(marker);
+ }
+ }
+ }
}
-
// *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it
}
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index 968b92d1e7..6b2d1b7c20 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -41,7 +41,7 @@
#include "lllivefile.h"
#include "llmemory.h"
#include "llstl.h" // for DeletePointer()
-#include "lltimer.h"
+#include "lleventtimer.h"
//
// Signal handling
diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h
index 5af7991006..f1b9091298 100644
--- a/indra/llcommon/llchat.h
+++ b/indra/llcommon/llchat.h
@@ -43,7 +43,8 @@ typedef enum e_chat_source_type
{
CHAT_SOURCE_SYSTEM = 0,
CHAT_SOURCE_AGENT = 1,
- CHAT_SOURCE_OBJECT = 2
+ CHAT_SOURCE_OBJECT = 2,
+ CHAT_SOURCE_UNKNOWN = 3
} EChatSourceType;
typedef enum e_chat_type
@@ -68,7 +69,8 @@ typedef enum e_chat_audible_level
typedef enum e_chat_style
{
CHAT_STYLE_NORMAL,
- CHAT_STYLE_IRC
+ CHAT_STYLE_IRC,
+ CHAT_STYLE_HISTORY
}EChatStyle;
// A piece of chat
@@ -79,6 +81,7 @@ public:
: mText(text),
mFromName(),
mFromID(),
+ mNotifId(),
mSourceType(CHAT_SOURCE_AGENT),
mChatType(CHAT_TYPE_NORMAL),
mAudible(CHAT_AUDIBLE_FULLY),
@@ -87,12 +90,14 @@ public:
mTimeStr(),
mPosAgent(),
mURL(),
- mChatStyle(CHAT_STYLE_NORMAL)
+ mChatStyle(CHAT_STYLE_NORMAL),
+ mSessionID()
{ }
std::string mText; // UTF-8 line of text
std::string mFromName; // agent or object name
LLUUID mFromID; // agent id or object id
+ LLUUID mNotifId;
EChatSourceType mSourceType;
EChatType mChatType;
EChatAudible mAudible;
@@ -102,6 +107,7 @@ public:
LLVector3 mPosAgent;
std::string mURL;
EChatStyle mChatStyle;
+ LLUUID mSessionID;
};
#endif
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index ca7e471bf2..de7f2ead74 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -152,7 +152,8 @@ void LLDate::toStream(std::ostream& s) const
s << '.' << std::setw(2)
<< (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100));
}
- s << 'Z';
+ s << 'Z'
+ << std::setfill(' ');
}
bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const
diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h
index 95178b41e7..4a2bfb9f3f 100644
--- a/indra/llcommon/lldictionary.h
+++ b/indra/llcommon/lldictionary.h
@@ -76,11 +76,16 @@ public:
return dictionary_iter->first;
}
}
- llassert(false);
- return Index(-1);
+ return notFound();
}
protected:
+ virtual Index notFound() const
+ {
+ // default is to assert
+ llassert(false);
+ return Index(-1);
+ }
void addEntry(Index index, Entry *entry)
{
if (lookup(index))
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index 5a4c644859..09812de2b8 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -242,7 +242,7 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
do { \
static LLError::CallSite _site( \
level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\
- if (_site.shouldLog()) \
+ if (LL_UNLIKELY(_site.shouldLog())) \
{ \
std::ostringstream* _out = LLError::Log::out(); \
(*_out)
diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h
index 7a970b1466..476d75380f 100644
--- a/indra/llcommon/llerrorlegacy.h
+++ b/indra/llcommon/llerrorlegacy.h
@@ -34,7 +34,7 @@
#ifndef LL_LLERRORLEGACY_H
#define LL_LLERRORLEGACY_H
-
+#include "llpreprocessor.h"
/*
LEGACY -- DO NOT USE THIS STUFF ANYMORE
@@ -75,6 +75,10 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
#define SHOW_ASSERT
#else // _DEBUG
+#ifdef LL_RELEASE_WITH_DEBUG_INFO
+#define SHOW_ASSERT
+#endif // LL_RELEASE_WITH_DEBUG_INFO
+
#ifdef RELEASE_SHOW_DEBUG
#define SHOW_DEBUG
#endif
@@ -103,7 +107,7 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl;
-#define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl;
+#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs << "ASSERT (" << #func << ")" << llendl;
#ifdef SHOW_ASSERT
#define llassert(func) llassert_always(func)
diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp
new file mode 100644
index 0000000000..d44e7ec1e6
--- /dev/null
+++ b/indra/llcommon/lleventtimer.cpp
@@ -0,0 +1,95 @@
+/**
+ * @file lleventtimer.cpp
+ * @brief Cross-platform objects for doing timing
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-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 "lleventtimer.h"
+
+#include "u64.h"
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// LLEventTimer Implementation
+//
+//////////////////////////////////////////////////////////////////////////////
+
+LLEventTimer::LLEventTimer(F32 period)
+: mEventTimer()
+{
+ mPeriod = period;
+}
+
+LLEventTimer::LLEventTimer(const LLDate& time)
+: mEventTimer()
+{
+ mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
+}
+
+
+LLEventTimer::~LLEventTimer()
+{
+}
+
+//static
+void LLEventTimer::updateClass()
+{
+ std::list<LLEventTimer*> completed_timers;
+
+ {
+ LLInstanceTrackerScopedGuard guard;
+ for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
+ {
+ LLEventTimer& timer = *iter++;
+ F32 et = timer.mEventTimer.getElapsedTimeF32();
+ if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
+ timer.mEventTimer.reset();
+ if ( timer.tick() )
+ {
+ completed_timers.push_back( &timer );
+ }
+ }
+ }
+ }
+
+ if ( completed_timers.size() > 0 )
+ {
+ for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
+ completed_iter != completed_timers.end();
+ completed_iter++ )
+ {
+ delete *completed_iter;
+ }
+ }
+}
+
+
diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h
new file mode 100644
index 0000000000..5181cce52d
--- /dev/null
+++ b/indra/llcommon/lleventtimer.h
@@ -0,0 +1,60 @@
+/**
+ * @file lleventtimer.h
+ * @brief Cross-platform objects for doing timing
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ *
+ * Copyright (c) 2000-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$
+ */
+
+#ifndef LL_EVENTTIMER_H
+#define LL_EVENTTIMER_H
+
+#include "stdtypes.h"
+#include "lldate.h"
+#include "llinstancetracker.h"
+#include "lltimer.h"
+
+// class for scheduling a function to be called at a given frequency (approximate, inprecise)
+class LL_COMMON_API LLEventTimer : protected LLInstanceTracker<LLEventTimer>
+{
+public:
+ LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
+ LLEventTimer(const LLDate& time);
+ virtual ~LLEventTimer();
+
+ //function to be called at the supplied frequency
+ // Normally return FALSE; TRUE will delete the timer after the function returns.
+ virtual BOOL tick() = 0;
+
+ static void updateClass();
+
+protected:
+ LLTimer mEventTimer;
+ F32 mPeriod;
+};
+
+#endif //LL_EVENTTIMER_H
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index f5c90291b8..48461df6ae 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -1,11 +1,11 @@
-/**
+/**
* @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.
- *
+ *
* 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
@@ -13,17 +13,17 @@
* ("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.
@@ -33,19 +33,43 @@
#ifndef LL_FASTTIMER_H
#define LL_FASTTIMER_H
-#include "llinstancetracker.h"
-
-#define FAST_TIMER_ON 1
-#define TIME_FAST_TIMERS 0
+// pull in the actual class definition
+#include "llfasttimer_class.h"
#if LL_WINDOWS
+//
+// Windows implementation of CPU clock
+//
+
+//
+// NOTE: put back in when we aren't using platform sdk anymore
+//
+// because MS has different signatures for these functions in winnt.h
+// need to rename them to avoid conflicts
+//#define _interlockedbittestandset _renamed_interlockedbittestandset
+//#define _interlockedbittestandreset _renamed_interlockedbittestandreset
+//#include <intrin.h>
+//#undef _interlockedbittestandset
+//#undef _interlockedbittestandreset
+
+//inline U32 LLFastTimer::getCPUClockCount32()
+//{
+// U64 time_stamp = __rdtsc();
+// return (U32)(time_stamp >> 8);
+//}
+//
+//// return full timer value, *not* shifted by 8 bits
+//inline U64 LLFastTimer::getCPUClockCount64()
+//{
+// return __rdtsc();
+//}
// shift off lower 8 bits for lower resolution but longer term timing
// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
-inline U32 get_cpu_clock_count_32()
+inline U32 LLFastTimer::getCPUClockCount32()
{
U32 ret_val;
- __asm
+ __asm
{
_emit 0x0f
_emit 0x31
@@ -58,10 +82,10 @@ inline U32 get_cpu_clock_count_32()
}
// return full timer value, *not* shifted by 8 bits
-inline U64 get_cpu_clock_count_64()
+inline U64 LLFastTimer::getCPUClockCount64()
{
U64 ret_val;
- __asm
+ __asm
{
_emit 0x0f
_emit 0x31
@@ -72,263 +96,71 @@ inline U64 get_cpu_clock_count_64()
}
return ret_val;
}
+#endif
+
+
+#if LL_LINUX || LL_SOLARIS
+//
+// Linux and Solaris implementation of CPU clock - all architectures.
+//
+// Try to use the MONOTONIC clock if available, this is a constant time counter
+// with nanosecond resolution (but not necessarily accuracy) and attempts are made
+// to synchronize this value between cores at kernel start. It should not be affected
+// by CPU frequency. If not available use the REALTIME clock, but this may be affected by
+// NTP adjustments or other user activity affecting the system time.
+inline U64 LLFastTimer::getCPUClockCount64()
+{
+ struct timespec tp;
+
+#ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time?
+ if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME
+#endif
+ clock_gettime(CLOCK_REALTIME,&tp);
+
+ return (tp.tv_sec*LLFastTimer::sClockResolution)+tp.tv_nsec;
+}
+
+inline U32 LLFastTimer::getCPUClockCount32()
+{
+ return (U32)(LLFastTimer::getCPUClockCount64() >> 8);
+}
+#endif // (LL_LINUX || LL_SOLARIS))
-#endif // LL_WINDOWS
-#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
-inline U32 get_cpu_clock_count_32()
-{
- U64 x;
- __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return (U32)x >> 8;
+#if (LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
+//
+// Mac x86 implementation of CPU clock
+inline U32 LLFastTimer::getCPUClockCount32()
+{
+ U64 x;
+ __asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
+ return (U32)(x >> 8);
}
-inline U32 get_cpu_clock_count_64()
-{
+inline U64 LLFastTimer::getCPUClockCount64()
+{
U64 x;
__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
- return x >> 8;
+ return x;
}
#endif
-#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__))
+
+#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__)))
//
-// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock
+// Mac PPC (deprecated) implementation of CPU clock
//
// Just use gettimeofday implementation for now
-inline U32 get_cpu_clock_count_32()
+inline U32 LLFastTimer::getCPUClockCount32()
{
- return (U32)get_clock_count();
+ return (U32)(get_clock_count()>>8);
}
-inline U32 get_cpu_clock_count_64()
-{
+inline U64 LLFastTimer::getCPUClockCount64()
+{
return get_clock_count();
}
#endif
-class LLMutex;
-
-#include <queue>
-#include "llsd.h"
-
-
-class LL_COMMON_API LLFastTimer
-{
-public:
- // 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();
-
- enum { HISTORY_NUM = 60 };
-
- 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();
-
- struct 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
- };
-
- 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<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>
- {
- public:
- DeclareTimer(const std::string& name, bool open);
- DeclareTimer(const std::string& name);
-
- static void updateCachedPointers();
-
- // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
- operator NamedTimer::FrameState&() { return *mFrameState; }
- private:
- NamedTimer& mTimer;
- NamedTimer::FrameState* mFrameState;
- };
-
-
-public:
- static LLMutex* sLogLock;
- static std::queue<LLSD> sLogQueue;
- static BOOL sLog;
- static BOOL sMetricLog;
-
- typedef std::vector<NamedTimer::FrameState> info_list_t;
- static info_list_t& getFrameStateList();
-
- enum RootTimerMarker { ROOT };
- LLFastTimer(RootTimerMarker);
-
- LLFastTimer(NamedTimer::FrameState& timer)
- : mFrameState(&timer)
- {
-#if TIME_FAST_TIMERS
- U64 timer_start = get_cpu_clock_count_64();
-#endif
-#if FAST_TIMER_ON
- NamedTimer::FrameState* frame_state = &timer;
- U32 cur_time = get_cpu_clock_count_32();
- mStartSelfTime = cur_time;
- mStartTotalTime = cur_time;
-
- 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);
-
- mLastTimer = sCurTimer;
- sCurTimer = this;
-#endif
-#if TIME_FAST_TIMERS
- U64 timer_end = get_cpu_clock_count_64();
- sTimerCycles += timer_end - timer_start;
-#endif
- }
-
- ~LLFastTimer()
- {
-#if TIME_FAST_TIMERS
- U64 timer_start = get_cpu_clock_count_64();
-#endif
-#if FAST_TIMER_ON
- NamedTimer::FrameState* frame_state = mFrameState;
- U32 cur_time = get_cpu_clock_count_32();
- frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
-
- frame_state->mActiveCount--;
- LLFastTimer* last_timer = mLastTimer;
- sCurTimer = last_timer;
-
- // store last caller to bootstrap tree creation
- frame_state->mLastCaller = last_timer->mFrameState;
-
- // we are only tracking self time, so subtract our total time delta from parents
- U32 total_time = cur_time - mStartTotalTime;
- last_timer->mStartSelfTime += total_time;
-#endif
-#if TIME_FAST_TIMERS
- U64 timer_end = get_cpu_clock_count_64();
- sTimerCycles += timer_end - timer_start;
- sTimerCalls++;
-#endif
- }
-
-
- // 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);
-
-public:
- static bool sPauseHistory;
- static bool sResetHistory;
- static U64 sTimerCycles;
- static U32 sTimerCalls;
-
-private:
- static LLFastTimer* sCurTimer;
- static S32 sCurFrameIndex;
- static S32 sLastFrameIndex;
- static U64 sLastFrameTime;
- static info_list_t* sTimerInfos;
-
- U32 mStartSelfTime; // start time + time of all child timers
- U32 mStartTotalTime; // start time + time of all child timers
- NamedTimer::FrameState* mFrameState;
- LLFastTimer* mLastTimer;
-};
-
#endif // LL_LLFASTTIMER_H
diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp
new file mode 100644
index 0000000000..2e5edb1f3b
--- /dev/null
+++ b/indra/llcommon/llfasttimer_class.cpp
@@ -0,0 +1,768 @@
+/**
+ * @file llfasttimer_class.cpp
+ * @brief Implementation of the fast timer.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewergpl$
+ *
+ * Copyright (c) 2004-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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"
+#include "llsingleton.h"
+#include "lltreeiterators.h"
+#include "llsdserialize.h"
+
+#include <boost/bind.hpp>
+
+#if LL_WINDOWS
+#elif LL_LINUX || LL_SOLARIS
+#include <sys/time.h>
+#include <sched.h>
+#elif LL_DARWIN
+#include <sys/time.h>
+#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;
+BOOL LLFastTimer::sMetricLog = FALSE;
+LLMutex* LLFastTimer::sLogLock = NULL;
+std::queue<LLSD> LLFastTimer::sLogQueue;
+
+#if LL_LINUX || LL_SOLARIS
+U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
+#else
+U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
+#endif
+
+std::vector<LLFastTimer::FrameState>* LLFastTimer::sTimerInfos = NULL;
+U64 LLFastTimer::sTimerCycles = 0;
+U32 LLFastTimer::sTimerCalls = 0;
+
+
+// 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;
+
+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<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> 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<NamedTimerFactory>
+{
+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<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* 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()
+{
+ DeclareTimer::LLInstanceTrackerScopedGuard guard;
+ // propagate frame state pointers to timer declarations
+ for (DeclareTimer::instance_iter it = guard.beginInstances();
+ it != guard.endInstances();
+ ++it)
+ {
+ // update cached pointer
+ it->mFrameState = &it->mTimer.getFrameState();
+ }
+}
+
+//static
+#if LL_LINUX || LL_SOLARIS || ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__)) )
+U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
+{
+ return sClockResolution >> 8;
+}
+#else // windows or x86-mac
+U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
+{
+ static U64 sCPUClockFrequency = U64(CProcessor().GetCPUFrequency(50));
+
+ // we drop the low-order byte in out timers, so report a lower frequency
+ 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)
+{
+ if (history_idx < 0)
+ {
+ // by default, show average number of calls
+ return llformat("%s (%d calls)", getName().c_str(), (S32)getCallAverage());
+ }
+ else
+ {
+ return llformat("%s (%d calls)", getName().c_str(), (S32)getHistoricalCalls(history_idx));
+ }
+}
+
+void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
+{
+ llassert_always(parent != this);
+ llassert_always(parent != NULL);
+
+ if (mParent)
+ {
+ // subtract our accumulated from previous parent
+ for (S32 i = 0; i < HISTORY_NUM; i++)
+ {
+ mParent->mCountHistory[i] -= mCountHistory[i];
+ }
+
+ // subtract average timing from previous parent
+ mParent->mCountAverage -= mCountAverage;
+
+ std::vector<NamedTimer*>& children = mParent->getChildren();
+ std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this);
+ if (found_it != children.end())
+ {
+ children.erase(found_it);
+ }
+ }
+
+ mParent = parent;
+ if (parent)
+ {
+ getFrameState().mParent = &parent->getFrameState();
+ parent->getChildren().push_back(this);
+ parent->mNeedsSorting = true;
+ }
+}
+
+S32 LLFastTimer::NamedTimer::getDepth()
+{
+ S32 depth = 0;
+ NamedTimer* timerp = mParent;
+ while(timerp)
+ {
+ depth++;
+ 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
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (instance_iter it = guard.beginInstances();
+ it != guard.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 = (timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1);
+ timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls;
+ timerp->mCallAverage = (timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1);
+ }
+ }
+}
+
+// static
+void LLFastTimer::NamedTimer::resetFrame()
+{
+ if (sLog)
+ { //output current frame counts to performance log
+ F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
+
+ F64 total_time = 0;
+ LLSD sd;
+
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (NamedTimer::instance_iter it = guard.beginInstances();
+ it != guard.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
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (NamedTimer::instance_iter it = guard.beginInstances();
+ it != guard.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
+ {
+ NamedTimer::LLInstanceTrackerScopedGuard guard;
+ for (NamedTimer::instance_iter it = guard.beginInstances();
+ it != guard.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<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren()
+{
+ return mChildren.begin();
+}
+
+std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren()
+{
+ return mChildren.end();
+}
+
+std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
+{
+ return mChildren;
+}
+
+//static
+void LLFastTimer::nextFrame()
+{
+ countsPerSecond(); // good place to calculate clock frequency
+ U64 frame_time = getCPUClockCount64();
+ if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff)
+ {
+ llinfos << "Slow frame, fast timers inaccurate" << llendl;
+ }
+
+ if (sPauseHistory)
+ {
+ sResetHistory = true;
+ }
+ else if (sResetHistory)
+ {
+ sLastFrameIndex = 0;
+ sCurFrameIndex = 0;
+ sResetHistory = false;
+ }
+ else // not paused
+ {
+ 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;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h
new file mode 100644
index 0000000000..ddb1a74793
--- /dev/null
+++ b/indra/llcommon/llfasttimer_class.h
@@ -0,0 +1,272 @@
+/**
+ * @file llfasttimer_class.h
+ * @brief Declaration of a 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$
+ */
+
+#ifndef LL_FASTTIMER_CLASS_H
+#define LL_FASTTIMER_CLASS_H
+
+#include "llinstancetracker.h"
+
+#define FAST_TIMER_ON 1
+#define TIME_FAST_TIMERS 0
+
+class LLMutex;
+
+#include <queue>
+#include "llsd.h"
+
+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<NamedTimer>
+ {
+ friend class DeclareTimer;
+ public:
+ ~NamedTimer();
+
+ enum { HISTORY_NUM = 60 };
+
+ 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();
+
+ 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<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);
+
+ 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
+ }
+
+ 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<LLSD> sLogQueue;
+ static BOOL sLog;
+ static BOOL sMetricLog;
+ static bool sPauseHistory;
+ static bool sResetHistory;
+ static U64 sTimerCycles;
+ static U32 sTimerCalls;
+
+ typedef std::vector<FrameState> 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;
+
+private:
+ static U32 getCPUClockCount32();
+ static U64 getCPUClockCount64();
+ static U64 sClockResolution;
+
+ 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_CLASS_H
diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp
index 079e670b1a..2610fe9e6a 100644
--- a/indra/llcommon/llfoldertype.cpp
+++ b/indra/llcommon/llfoldertype.cpp
@@ -59,6 +59,11 @@ class LLFolderDictionary : public LLSingleton<LLFolderDictionary>,
{
public:
LLFolderDictionary();
+protected:
+ virtual LLFolderType::EType notFound() const
+ {
+ return LLFolderType::FT_NONE;
+ }
};
LLFolderDictionary::LLFolderDictionary()
diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp
new file mode 100644
index 0000000000..c962cb5be1
--- /dev/null
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -0,0 +1,20 @@
+/**
+ * @file lllinstancetracker.cpp
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * Copyright (c) 2009, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "llinstancetracker.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+
+// llinstancetracker.h is presently header-only. This file exists only because our CMake
+// test macro ADD_BUILD_TEST requires it.
+int dummy = 0;
diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h
index 11fe523651..9df7998273 100644
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -98,7 +98,10 @@ private:
mKey = key;
getMap_()[key] = static_cast<T*>(this);
}
- void remove_() { getMap_().erase(mKey); }
+ void remove_()
+ {
+ getMap_().erase(mKey);
+ }
static InstanceMap& getMap_()
{
@@ -129,31 +132,65 @@ public:
/// for completeness of analogy with the generic implementation
static T* getInstance(T* k) { return k; }
- static key_iter beginKeys() { return getSet_().begin(); }
- static key_iter endKeys() { return getSet_().end(); }
- static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
- static instance_iter endInstances() { return instance_iter(getSet_().end()); }
static S32 instanceCount() { return getSet_().size(); }
+ // Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
+ // that it treats deletes of this type as errors as long as there is an instance of
+ // this class alive in scope somewhere (i.e. deleting while iterating is bad).
+ class LLInstanceTrackerScopedGuard
+ {
+ public:
+ LLInstanceTrackerScopedGuard()
+ {
+ ++sIterationNestDepth;
+ }
+
+ ~LLInstanceTrackerScopedGuard()
+ {
+ --sIterationNestDepth;
+ }
+
+ static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
+ static instance_iter endInstances() { return instance_iter(getSet_().end()); }
+ static key_iter beginKeys() { return getSet_().begin(); }
+ static key_iter endKeys() { return getSet_().end(); }
+ };
+
protected:
- LLInstanceTracker() { getSet_().insert(static_cast<T*>(this)); }
- virtual ~LLInstanceTracker() { getSet_().erase(static_cast<T*>(this)); }
+ LLInstanceTracker()
+ {
+ // it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
+ //llassert(sIterationNestDepth == 0);
+ getSet_().insert(static_cast<T*>(this));
+ }
+ virtual ~LLInstanceTracker()
+ {
+ // it's unsafe to delete instances of this type while all instances are being iterated over.
+ llassert(sIterationNestDepth == 0);
+ getSet_().erase(static_cast<T*>(this));
+ }
- LLInstanceTracker(const LLInstanceTracker& other) { getSet_().insert(static_cast<T*>(this)); }
+ LLInstanceTracker(const LLInstanceTracker& other)
+ {
+ //llassert(sIterationNestDepth == 0);
+ getSet_().insert(static_cast<T*>(this));
+ }
- static InstanceSet& getSet_() // called after getReady() but before go()
- {
- if (! sInstances)
- {
- sInstances = new InstanceSet;
- }
- return *sInstances;
- }
+ static InstanceSet& getSet_()
+ {
+ if (! sInstances)
+ {
+ sInstances = new InstanceSet;
+ }
+ return *sInstances;
+ }
static InstanceSet* sInstances;
+ static S32 sIterationNestDepth;
};
template <typename T, typename KEY> typename LLInstanceTracker<T, KEY>::InstanceMap* LLInstanceTracker<T, KEY>::sInstances = NULL;
template <typename T> typename LLInstanceTracker<T, T*>::InstanceSet* LLInstanceTracker<T, T*>::sInstances = NULL;
+template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
#endif
diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp
index effda6c49c..5ca90d82ba 100644
--- a/indra/llcommon/lllivefile.cpp
+++ b/indra/llcommon/lllivefile.cpp
@@ -33,7 +33,7 @@
#include "lllivefile.h"
#include "llframetimer.h"
-#include "lltimer.h"
+#include "lleventtimer.h"
const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f;
diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h
index 2c37eadcc6..e6c736a263 100644
--- a/indra/llcommon/llpointer.h
+++ b/indra/llcommon/llpointer.h
@@ -95,7 +95,6 @@ public:
bool notNull() const { return (mPointer != NULL); }
operator Type*() const { return mPointer; }
- operator const Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index 5eefa6a16b..1c1503ca7b 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -55,13 +55,28 @@
#define LL_BIG_ENDIAN 1
#endif
+
// Per-compiler switches
+
#ifdef __GNUC__
#define LL_FORCE_INLINE inline __attribute__((always_inline))
#else
#define LL_FORCE_INLINE __forceinline
#endif
+// Mark-up expressions with branch prediction hints. Do NOT use
+// this with reckless abandon - it's an obfuscating micro-optimization
+// outside of inner loops or other places where you are OVERWHELMINGLY
+// sure which way an expression almost-always evaluates.
+#if __GNUC__ >= 3
+# define LL_LIKELY(EXPR) __builtin_expect (!!(EXPR), true)
+# define LL_UNLIKELY(EXPR) __builtin_expect (!!(EXPR), false)
+#else
+# define LL_LIKELY(EXPR) (EXPR)
+# define LL_UNLIKELY(EXPR) (EXPR)
+#endif
+
+
// Figure out differences between compilers
#if defined(__GNUC__)
#define GCC_VERSION (__GNUC__ * 10000 \
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 469e544b16..8a4a4a8f9a 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -281,7 +281,8 @@ bool CProcessor::AnalyzeIntelProcessor()
// already have a string here from GetCPUInfo(). JC
if ( CPUInfo.uiBrandID < LL_ARRAY_SIZE(INTEL_BRAND) )
{
- strcpy(CPUInfo.strBrandID, INTEL_BRAND[CPUInfo.uiBrandID]);
+ strncpy(CPUInfo.strBrandID, INTEL_BRAND[CPUInfo.uiBrandID], sizeof(CPUInfo.strBrandID)-1);
+ CPUInfo.strBrandID[sizeof(CPUInfo.strBrandID)-1]='\0';
if (CPUInfo.uiBrandID == 3 && CPUInfo.uiModel == 6)
{
diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp
index 33b6875fb0..c90b52f482 100644
--- a/indra/llcommon/llrefcount.cpp
+++ b/indra/llcommon/llrefcount.cpp
@@ -35,6 +35,17 @@
#include "llerror.h"
+LLRefCount::LLRefCount(const LLRefCount& other)
+: mRef(0)
+{
+}
+
+LLRefCount& LLRefCount::operator=(const LLRefCount&)
+{
+ // do nothing, since ref count is specific to *this* reference
+ return *this;
+}
+
LLRefCount::LLRefCount() :
mRef(0)
{
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 9ab844eb22..a18f6706a9 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -41,22 +41,20 @@
class LL_COMMON_API LLRefCount
{
-private:
- LLRefCount(const LLRefCount& other); // no implementation
-private:
- LLRefCount& operator=(const LLRefCount&); // no implementation
protected:
+ LLRefCount(const LLRefCount& other);
+ LLRefCount& operator=(const LLRefCount&);
virtual ~LLRefCount(); // use unref()
public:
LLRefCount();
- void ref()
+ void ref() const
{
mRef++;
}
- S32 unref()
+ S32 unref() const
{
llassert(mRef >= 1);
if (0 == --mRef)
@@ -67,13 +65,15 @@ public:
return mRef;
}
+ //NOTE: when passing around a const LLRefCount object, this can return different results
+ // at different types, since mRef is mutable
S32 getNumRefs() const
{
return mRef;
}
private:
- S32 mRef;
+ mutable S32 mRef;
};
#endif
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index 7e1c2e35e0..fca173df47 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -139,12 +139,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti
case LLSD::TypeBoolean:
ostr << pre << "<boolean>";
if(mBoolAlpha ||
-#if( LL_WINDOWS || __GNUC__ > 2)
(ostr.flags() & std::ios::boolalpha)
-#else
- (ostr.flags() & 0x0100)
-#endif
- )
+ )
{
ostr << (data.asBoolean() ? "true" : "false");
}
@@ -511,12 +507,7 @@ void LLSDXMLParser::Impl::reset()
mSkipping = false;
-#if( LL_WINDOWS || __GNUC__ > 2)
mCurrentKey.clear();
-#else
- mCurrentKey = std::string();
-#endif
-
XML_ParserReset(mParser, "utf-8");
XML_SetUserData(mParser, this);
@@ -644,11 +635,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch
LLSD& newElement = map[mCurrentKey];
mStack.push_back(&newElement);
-#if( LL_WINDOWS || __GNUC__ > 2)
mCurrentKey.clear();
-#else
- mCurrentKey = std::string();
-#endif
}
else if (mStack.back()->isArray())
{
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 31e70e0fe4..62cedcde4e 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -882,6 +882,7 @@ void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
}
string.assign(t, size);
+ delete[] t;
}
}
diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp
index ef3e8dbc94..25b768079b 100644
--- a/indra/llcommon/lltimer.cpp
+++ b/indra/llcommon/lltimer.cpp
@@ -555,54 +555,3 @@ void secondsToTimecodeString(F32 current_time, std::string& tcstring)
}
-//////////////////////////////////////////////////////////////////////////////
-//
-// LLEventTimer Implementation
-//
-//////////////////////////////////////////////////////////////////////////////
-
-LLEventTimer::LLEventTimer(F32 period)
-: mEventTimer()
-{
- mPeriod = period;
-}
-
-LLEventTimer::LLEventTimer(const LLDate& time)
-: mEventTimer()
-{
- mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
-}
-
-
-LLEventTimer::~LLEventTimer()
-{
-}
-
-void LLEventTimer::updateClass()
-{
- std::list<LLEventTimer*> completed_timers;
- for (instance_iter iter = beginInstances(); iter != endInstances(); )
- {
- LLEventTimer& timer = *iter++;
- F32 et = timer.mEventTimer.getElapsedTimeF32();
- if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
- timer.mEventTimer.reset();
- if ( timer.tick() )
- {
- completed_timers.push_back( &timer );
- }
- }
- }
-
- if ( completed_timers.size() > 0 )
- {
- for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
- completed_iter != completed_timers.end();
- completed_iter++ )
- {
- delete *completed_iter;
- }
- }
-}
-
-
diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h
index d009c0f5f7..baba95bfa1 100644
--- a/indra/llcommon/lltimer.h
+++ b/indra/llcommon/lltimer.h
@@ -39,8 +39,6 @@
#include <limits.h>
#include "stdtypes.h"
-#include "lldate.h"
-#include "llinstancetracker.h"
#include <string>
#include <list>
@@ -171,25 +169,6 @@ LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_dayli
LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring);
LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring);
-// class for scheduling a function to be called at a given frequency (approximate, inprecise)
-class LL_COMMON_API LLEventTimer : protected LLInstanceTracker<LLEventTimer>
-{
-public:
- LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds
- LLEventTimer(const LLDate& time);
- virtual ~LLEventTimer();
-
- //function to be called at the supplied frequency
- // Normally return FALSE; TRUE will delete the timer after the function returns.
- virtual BOOL tick() = 0;
-
- static void updateClass();
-
-protected:
- LLTimer mEventTimer;
- F32 mPeriod;
-};
-
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
#endif
diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h
index c946566e84..cb1304c54e 100644
--- a/indra/llcommon/lltreeiterators.h
+++ b/indra/llcommon/lltreeiterators.h
@@ -343,20 +343,20 @@ public:
/// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
- LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
- mBeginFunc(beginfunc),
- mEndFunc(endfunc),
- mSkipChildren(false)
+ LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
+ : mBeginFunc(beginfunc),
+ mEndFunc(endfunc),
+ mSkipChildren(false)
{
// Only push back this node if it's non-NULL!
if (node)
mPending.push_back(node);
}
/// Instantiate an LLTreeDFSIter to mark the end of the walk
- LLTreeDFSIter() {}
+ LLTreeDFSIter() : mSkipChildren(false) {}
- /// flags iterator logic to skip traversing children of current node on next increment
- void skipDescendants(bool skip = true) { mSkipChildren = skip; }
+ /// flags iterator logic to skip traversing children of current node on next increment
+ void skipDescendants(bool skip = true) { mSkipChildren = skip; }
private:
/// leverage boost::iterator_facade
@@ -405,8 +405,8 @@ private:
func_type mBeginFunc;
/// functor to extract end() child iterator
func_type mEndFunc;
- /// flag which controls traversal of children (skip children of current node if true)
- bool mSkipChildren;
+ /// flag which controls traversal of children (skip children of current node if true)
+ bool mSkipChildren;
};
/**
@@ -451,21 +451,21 @@ public:
/// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
- LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
- mBeginFunc(beginfunc),
- mEndFunc(endfunc),
- mSkipAncestors(false)
- {
+ LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
+ : mBeginFunc(beginfunc),
+ mEndFunc(endfunc),
+ mSkipAncestors(false)
+ {
if (! node)
return;
mPending.push_back(typename list_type::value_type(node, false));
makeCurrent();
}
/// Instantiate an LLTreeDFSPostIter to mark the end of the walk
- LLTreeDFSPostIter() {}
+ LLTreeDFSPostIter() : mSkipAncestors(false) {}
- /// flags iterator logic to skip traversing ancestors of current node on next increment
- void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
+ /// flags iterator logic to skip traversing ancestors of current node on next increment
+ void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
private:
/// leverage boost::iterator_facade
diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp
index f6e8f01f0e..9d4f3a98f0 100644
--- a/indra/llcommon/lluri.cpp
+++ b/indra/llcommon/lluri.cpp
@@ -46,10 +46,21 @@
void encode_character(std::ostream& ostr, std::string::value_type val)
{
- ostr << "%" << std::uppercase << std::hex << std::setw(2) << std::setfill('0')
+ ostr << "%"
+
+ << std::uppercase
+ << std::hex
+ << std::setw(2)
+ << std::setfill('0')
+
// VWR-4010 Cannot cast to U32 because sign-extension on
// chars > 128 will result in FFFFFFC3 instead of F3.
- << static_cast<S32>(static_cast<U8>(val));
+ << static_cast<S32>(static_cast<U8>(val))
+
+ // reset stream state
+ << std::nouppercase
+ << std::dec
+ << std::setfill(' ');
}
// static
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 82c736266d..1b0e03cb2a 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -188,6 +188,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
: mWorkerThread(workerthread),
mWorkerClassName(name),
mRequestHandle(LLWorkerThread::nullHandle()),
+ mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
mMutex(NULL),
mWorkFlags(0)
{
diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp
index 7415f2d33b..4bb3ec2922 100644
--- a/indra/llcommon/tests/llinstancetracker_test.cpp
+++ b/indra/llcommon/tests/llinstancetracker_test.cpp
@@ -138,23 +138,29 @@ namespace tut
keys.insert(&one);
keys.insert(&two);
keys.insert(&three);
- for (Unkeyed::key_iter ki(Unkeyed::beginKeys()), kend(Unkeyed::endKeys());
- ki != kend; ++ki)
- {
- ensure_equals("spurious key", keys.erase(*ki), 1);
- }
+ {
+ Unkeyed::LLInstanceTrackerScopedGuard guard;
+ for (Unkeyed::key_iter ki(guard.beginKeys()), kend(guard.endKeys());
+ ki != kend; ++ki)
+ {
+ ensure_equals("spurious key", keys.erase(*ki), 1);
+ }
+ }
ensure_equals("unreported key", keys.size(), 0);
KeySet instances;
instances.insert(&one);
instances.insert(&two);
instances.insert(&three);
- for (Unkeyed::instance_iter ii(Unkeyed::beginInstances()), iend(Unkeyed::endInstances());
- ii != iend; ++ii)
- {
- Unkeyed& ref = *ii;
- ensure_equals("spurious instance", instances.erase(&ref), 1);
- }
+ {
+ Unkeyed::LLInstanceTrackerScopedGuard guard;
+ for (Unkeyed::instance_iter ii(guard.beginInstances()), iend(guard.endInstances());
+ ii != iend; ++ii)
+ {
+ Unkeyed& ref = *ii;
+ ensure_equals("spurious instance", instances.erase(&ref), 1);
+ }
+ }
ensure_equals("unreported instance", instances.size(), 0);
}
} // namespace tut