diff options
Diffstat (limited to 'indra/llcommon')
92 files changed, 6028 insertions, 10826 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 3a4a8facc2..bf99a4c3a0 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -75,8 +75,10 @@ set(llcommon_SOURCE_FILES llmetrics.cpp llmetricperformancetester.cpp llmortician.cpp + llmutex.cpp lloptioninterface.cpp llptrto.cpp + llpredicate.cpp llprocess.cpp llprocessor.cpp llqueuedthread.cpp @@ -90,7 +92,6 @@ set(llcommon_SOURCE_FILES llsdutil.cpp llsecondlifeurls.cpp llsingleton.cpp - llstat.cpp llstacktrace.cpp llstreamqueue.cpp llstreamtools.cpp @@ -98,14 +99,15 @@ set(llcommon_SOURCE_FILES llstringtable.cpp llsys.cpp llthread.cpp + llthreadlocalstorage.cpp llthreadsafequeue.cpp lltimer.cpp + lltrace.cpp + lltracerecording.cpp + lltracethreadrecorder.cpp lluri.cpp lluuid.cpp llworkerthread.cpp - metaclass.cpp - metaproperty.cpp - reflective.cpp timing.cpp u64.cpp ) @@ -115,7 +117,6 @@ set(llcommon_HEADER_FILES bitpack.h ctype_workaround.h - doublelinkedlist.h fix_macros.h imageids.h indra_constants.h @@ -129,7 +130,6 @@ set(llcommon_HEADER_FILES llapp.h llapr.h llassettype.h - llassoclist.h llavatarconstants.h llbase32.h llbase64.h @@ -143,18 +143,14 @@ set(llcommon_HEADER_FILES llcriticaldamp.h llcursortypes.h lldarray.h - lldarrayptr.h lldate.h lldefs.h lldependencies.h lldeleteutils.h lldepthstack.h lldictionary.h - lldlinked.h lldoubledispatch.h - lldqueueptr.h llendianswizzle.h - llenum.h llerror.h llerrorcontrol.h llerrorlegacy.h @@ -178,18 +174,15 @@ set(llcommon_HEADER_FILES llhash.h llheartbeat.h llhttpstatuscodes.h - llindexedqueue.h llinitparam.h llinstancetracker.h llkeythrottle.h - lllazy.h llleap.h llleaplistener.h lllistenerwrapper.h lllinkedqueue.h llliveappconfig.h lllivefile.h - lllocalidhashmap.h lllog.h lllslconstants.h llmap.h @@ -199,15 +192,15 @@ set(llcommon_HEADER_FILES llmetrics.h llmetricperformancetester.h llmortician.h + llmutex.h llnametable.h lloptioninterface.h llpointer.h + llpredicate.h llpreprocessor.h llpriqueuemap.h llprocess.h llprocessor.h - llptrskiplist.h - llptrskipmap.h llptrto.h llqueuedthread.h llrand.h @@ -224,12 +217,7 @@ set(llcommon_HEADER_FILES llsecondlifeurls.h llsimplehash.h llsingleton.h - llskiplist.h - llskipmap.h - llsortedvector.h - llstack.h llstacktrace.h - llstat.h llstatenums.h llstl.h llstreamqueue.h @@ -239,22 +227,21 @@ set(llcommon_HEADER_FILES llstringtable.h llsys.h llthread.h + llthreadlocalstorage.h llthreadsafequeue.h lltimer.h + lltrace.h + lltracerecording.h + lltracethreadrecorder.h lltreeiterators.h - lltypeinfolookup.h + llunit.h lluri.h lluuid.h - lluuidhashmap.h llversionserver.h + llwin32headers.h + llwin32headerslean.h llworkerthread.h ll_template_cast.h - metaclass.h - metaclasst.h - metaproperty.h - metapropertyt.h - reflective.h - reflectivet.h roles_constants.h stdenums.h stdtypes.h @@ -326,7 +313,6 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}") @@ -334,7 +320,7 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}") LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs};${BOOST_CONTEXT_LIBRARY}") diff --git a/indra/llcommon/doublelinkedlist.h b/indra/llcommon/doublelinkedlist.h deleted file mode 100755 index 0aeaa69df3..0000000000 --- a/indra/llcommon/doublelinkedlist.h +++ /dev/null @@ -1,1397 +0,0 @@ -/** - * @file doublelinkedlist.h - * @brief Provides a standard doubly linked list for fun and profit. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_DOUBLELINKEDLIST_H -#define LL_DOUBLELINKEDLIST_H - -#include "llerror.h" -#include "llrand.h" - -// node that actually contains the data -template <class DATA_TYPE> class LLDoubleLinkedNode -{ -public: - DATA_TYPE *mDatap; - LLDoubleLinkedNode *mNextp; - LLDoubleLinkedNode *mPrevp; - - -public: - // assign the mDatap pointer - LLDoubleLinkedNode(DATA_TYPE *data); - - // destructor does not, by default, destroy associated data - // however, the mDatap must be NULL to ensure that we aren't causing memory leaks - ~LLDoubleLinkedNode(); - - // delete associated data and NULL out pointer - void deleteData(); - - // remove associated data and NULL out pointer - void removeData(); -}; - - -const U32 LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH = 4; - -template <class DATA_TYPE> class LLDoubleLinkedList -{ -private: - LLDoubleLinkedNode<DATA_TYPE> mHead; // head node - LLDoubleLinkedNode<DATA_TYPE> mTail; // tail node - LLDoubleLinkedNode<DATA_TYPE> *mQueuep; // The node in the batter's box - LLDoubleLinkedNode<DATA_TYPE> *mCurrentp; // The node we're talking about - - // The state stack allows nested exploration of the LLDoubleLinkedList - // but should be used with great care - LLDoubleLinkedNode<DATA_TYPE> *mQueuepStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH]; - LLDoubleLinkedNode<DATA_TYPE> *mCurrentpStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH]; - U32 mStateStackDepth; - U32 mCount; - - // mInsertBefore is a pointer to a user-set function that returns - // TRUE if "first" should be located before "second" - // NOTE: mInsertBefore() should never return TRUE when ("first" == "second") - // or never-ending loops can occur - BOOL (*mInsertBefore)(DATA_TYPE *first, DATA_TYPE *second); - -public: - LLDoubleLinkedList(); - - // destructor destroys list and nodes, but not data in nodes - ~LLDoubleLinkedList(); - - // put data into a node and stick it at the front of the list - // set mCurrentp to mQueuep - void addData(DATA_TYPE *data); - - // put data into a node and stick it at the end of the list - // set mCurrentp to mQueuep - void addDataAtEnd(DATA_TYPE *data); - - S32 getLength() const; - // search the list starting at mHead.mNextp and remove the link with mDatap == data - // set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL removeData(const DATA_TYPE *data); - - // search the list starting at mHead.mNextp and delete the link with mDatap == data - // set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL deleteData(DATA_TYPE *data); - - // remove all nodes from the list and delete the associated data - void deleteAllData(); - - // remove all nodes from the list but do not delete data - void removeAllNodes(); - - BOOL isEmpty(); - - // check to see if data is in list - // set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL checkData(const DATA_TYPE *data); - - // NOTE: This next two funtions are only included here - // for those too familiar with the LLLinkedList template class. - // They are depreciated. resetList() is unecessary while - // getCurrentData() is identical to getNextData() and has - // a misleading name. - // - // The recommended way to loop through a list is as follows: - // - // datap = list.getFirstData(); - // while (datap) - // { - // /* do stuff */ - // datap = list.getNextData(); - // } - - // place mQueuep on mHead node - void resetList(); - - // return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - // NOTE: this function is identical to getNextData() - DATA_TYPE *getCurrentData(); - - - // reset the list and return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - DATA_TYPE *getFirstData(); - - - // reset the list and return the data at position n, set mCurentp - // to that node and bump mQueuep down the list - // Note: n=0 will behave like getFirstData() - DATA_TYPE *getNthData(U32 n); - - // reset the list and return the last data in it, - // set mCurrentp to that node and bump mQueuep up the list - DATA_TYPE *getLastData(); - - // return data in mQueuep, - // set mCurrentp mQueuep and bump mQueuep down the list - DATA_TYPE *getNextData(); - - // return the data in mQueuep, - // set mCurrentp to mQueuep and bump mQueuep up the list - DATA_TYPE *getPreviousData(); - - // remove the Node at mCurrentp - // set mCurrentp to mQueuep - void removeCurrentData(); - - // delete the Node at mCurrentp - // set mCurrentp to mQueuep - void deleteCurrentData(); - - // remove the Node at mCurrentp and insert it into newlist - // set mCurrentp to mQueuep - void moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist); - - // insert the node in front of mCurrentp - // set mCurrentp to mQueuep - void insertNode(LLDoubleLinkedNode<DATA_TYPE> *node); - - // insert the data in front of mCurrentp - // set mCurrentp to mQueuep - void insertData(DATA_TYPE *data); - - // if mCurrentp has a previous node then : - // * swaps mCurrentp with its previous - // * set mCurrentp to mQueuep - // (convenient for forward bubble-sort) - // otherwise does nothing - void swapCurrentWithPrevious(); - - // if mCurrentp has a next node then : - // * swaps mCurrentp with its next - // * set mCurrentp to mQueuep - // (convenient for backwards bubble-sort) - // otherwise does nothing - void swapCurrentWithNext(); - - // move mCurrentp to the front of the list - // set mCurrentp to mQueuep - void moveCurrentToFront(); - - // move mCurrentp to the end of the list - // set mCurrentp to mQueuep - void moveCurrentToEnd(); - - // set mInsertBefore - void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second)); - - // add data in front of first node for which mInsertBefore(datap, node->mDatap) returns TRUE - // set mCurrentp to mQueuep - BOOL addDataSorted(DATA_TYPE *datap); - - // sort the list using bubble-sort - // Yes, this is a different name than the same function in LLLinkedList. - // When it comes time for a name consolidation hopefully this one will win. - BOOL bubbleSort(); - - // does a single bubble sort pass on the list - BOOL lazyBubbleSort(); - - // returns TRUE if state successfully pushed (state stack not full) - BOOL pushState(); - - // returns TRUE if state successfully popped (state stack not empty) - BOOL popState(); - - // empties the state stack - void clearStateStack(); - - // randomly move the the links in the list for debug or (Discordian) purposes - // sets mCurrentp and mQueuep to top of list - void scramble(); - -private: - // add node to beginning of list - // set mCurrentp to mQueuep - void addNode(LLDoubleLinkedNode<DATA_TYPE> *node); - - // add node to end of list - // set mCurrentp to mQueuep - void addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node); -}; - -//#endif - -//////////////////////////////////////////////////////////////////////////////////////////// - -// doublelinkedlist.cpp -// LLDoubleLinkedList template class implementation file. -// Provides a standard doubly linked list for fun and profit. -// -// Copyright 2001, Linden Research, Inc. - -//#include "llerror.h" -//#include "doublelinkedlist.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// LLDoubleLinkedNode -////////////////////////////////////////////////////////////////////////////////////////// - - -// assign the mDatap pointer -template <class DATA_TYPE> -LLDoubleLinkedNode<DATA_TYPE>::LLDoubleLinkedNode(DATA_TYPE *data) : - mDatap(data), mNextp(NULL), mPrevp(NULL) -{ -} - - -// destructor does not, by default, destroy associated data -// however, the mDatap must be NULL to ensure that we aren't causing memory leaks -template <class DATA_TYPE> -LLDoubleLinkedNode<DATA_TYPE>::~LLDoubleLinkedNode() -{ - if (mDatap) - { - llerror("Attempting to call LLDoubleLinkedNode destructor with a non-null mDatap!", 1); - } -} - - -// delete associated data and NULL out pointer -template <class DATA_TYPE> -void LLDoubleLinkedNode<DATA_TYPE>::deleteData() -{ - delete mDatap; - mDatap = NULL; -} - - -template <class DATA_TYPE> -void LLDoubleLinkedNode<DATA_TYPE>::removeData() -{ - mDatap = NULL; -} - - -////////////////////////////////////////////////////////////////////////////////////// -// LLDoubleLinkedList -////////////////////////////////////////////////////////////////////////////////////// - -// <------- up ------- -// -// mCurrentp -// mQueuep | -// | | -// | | -// .------. .------. .------. .------. -// | |---->| |---->| |----->| |-----> NULL -// NULL <-----| |<----| |<----| |<-----| | -// _'------' '------' '------' '------:_ -// .------. /| | | |\ .------. -// NULL <-----|mHead |/ | mQueuep \|mTail |-----> NULL -// | | mCurrentp | | -// '------' '------' -// -------- down ---------> - -template <class DATA_TYPE> -LLDoubleLinkedList<DATA_TYPE>::LLDoubleLinkedList() -: mHead(NULL), mTail(NULL), mQueuep(NULL) -{ - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; - mInsertBefore = NULL; -} - - -// destructor destroys list and nodes, but not data in nodes -template <class DATA_TYPE> -LLDoubleLinkedList<DATA_TYPE>::~LLDoubleLinkedList() -{ - removeAllNodes(); -} - - -// put data into a node and stick it at the front of the list -// doesn't change mCurrentp nor mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addData(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0); - } - - // make the new node - LLDoubleLinkedNode<DATA_TYPE> *temp = new LLDoubleLinkedNode<DATA_TYPE> (data); - - // add the node to the front of the list - temp->mPrevp = NULL; - temp->mNextp = mHead.mNextp; - mHead.mNextp = temp; - - // if there's something in the list, fix its back pointer - if (temp->mNextp) - { - temp->mNextp->mPrevp = temp; - } - // otherwise, fix the tail of the list - else - { - mTail.mPrevp = temp; - } - - mCount++; -} - - -// put data into a node and stick it at the end of the list -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addDataAtEnd(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0); - } - - // make the new node - LLDoubleLinkedNode<DATA_TYPE> *nodep = new LLDoubleLinkedNode<DATA_TYPE>(data); - - addNodeAtEnd(nodep); - mCount++; -} - - -// search the list starting at mHead.mNextp and remove the link with mDatap == data -// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::removeData(const DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::removeData()", 0); - } - - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - b_found = TRUE; - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->removeData(); - delete mCurrentp; - mCount--; - break; - } - mCurrentp = mCurrentp->mNextp; - } - - // reset the list back to where it was - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - - return b_found; -} - - -// search the list starting at mHead.mNextp and delete the link with mDatap == data -// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::deleteData(DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::deleteData()", 0); - } - - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - b_found = TRUE; - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->deleteData(); - delete mCurrentp; - mCount--; - break; - } - mCurrentp = mCurrentp->mNextp; - } - - // reset the list back to where it was - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - - return b_found; -} - - -// remove all nodes from the list and delete the associated data -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::deleteAllData() -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - mQueuep = mCurrentp->mNextp; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = mQueuep; - } - - // reset mHead and mQueuep - mHead.mNextp = NULL; - mTail.mPrevp = NULL; - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; -} - - -// remove all nodes from the list but do not delete associated data -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::removeAllNodes() -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - mQueuep = mCurrentp->mNextp; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = mQueuep; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mTail.mPrevp = NULL; - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; -} - -template <class DATA_TYPE> -S32 LLDoubleLinkedList<DATA_TYPE>::getLength() const -{ -// U32 length = 0; -// for (LLDoubleLinkedNode<DATA_TYPE>* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp) -// { -// length++; -// } - return mCount; -} - -// check to see if data is in list -// set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::checkData(const DATA_TYPE *data) -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - mQueuep = mCurrentp; - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - - mCurrentp = mQueuep; - return FALSE; -} - -// NOTE: This next two funtions are only included here -// for those too familiar with the LLLinkedList template class. -// They are depreciated. resetList() is unecessary while -// getCurrentData() is identical to getNextData() and has -// a misleading name. -// -// The recommended way to loop through a list is as follows: -// -// datap = list.getFirstData(); -// while (datap) -// { -// /* do stuff */ -// datap = list.getNextData(); -// } - - // place mCurrentp and mQueuep on first node - template <class DATA_TYPE> - void LLDoubleLinkedList<DATA_TYPE>::resetList() - { - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - } - - - // return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - template <class DATA_TYPE> - DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getCurrentData() - { - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } - } - - -// reset the list and return the data currently pointed to, -// set mCurrentp to that node and bump mQueuep down the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getFirstData() -{ - mQueuep = mHead.mNextp; - mCurrentp = mQueuep; - if (mQueuep) - { - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// reset the list and return the data at position n, set mCurentp -// to that node and bump mQueuep down the list -// Note: n=0 will behave like getFirstData() -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNthData(U32 n) -{ - mCurrentp = mHead.mNextp; - - if (mCurrentp) - { - for (U32 i=0; i<n; i++) - { - mCurrentp = mCurrentp->mNextp; - if (!mCurrentp) - { - break; - } - } - } - - if (mCurrentp) - { - // bump mQueuep down the list - mQueuep = mCurrentp->mNextp; - return mCurrentp->mDatap; - } - else - { - mQueuep = NULL; - return NULL; - } -} - - -// reset the list and return the last data in it, -// set mCurrentp to that node and bump mQueuep up the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getLastData() -{ - mQueuep = mTail.mPrevp; - mCurrentp = mQueuep; - if (mQueuep) - { - mQueuep = mQueuep->mPrevp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// return the data in mQueuep, -// set mCurrentp to mQueuep and bump mQueuep down the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNextData() -{ - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// return the data in mQueuep, -// set mCurrentp to mQueuep and bump mQueuep up the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getPreviousData() -{ - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mPrevp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// remove the Node at mCurrentp -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::removeCurrentData() -{ - if (mCurrentp) - { - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->removeData(); - delete mCurrentp; - mCount--; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// delete the Node at mCurrentp -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::deleteCurrentData() -{ - if (mCurrentp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the LLDoubleLinkedNode - mCurrentp->deleteData(); - delete mCurrentp; - mCount--; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// remove the Node at mCurrentp and insert it into newlist -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist) -{ - if (mCurrentp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // move the node to the new list - newlist->addNode(mCurrentp); - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// Inserts the node previous to mCurrentp -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::insertNode(LLDoubleLinkedNode<DATA_TYPE> *nodep) -{ - // don't allow pointer to NULL to be passed - if (!nodep) - { - llerror("NULL pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - if (!nodep->mDatap) - { - llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - - if (mCurrentp) - { - if (mCurrentp->mPrevp) - { - nodep->mPrevp = mCurrentp->mPrevp; - nodep->mNextp = mCurrentp; - mCurrentp->mPrevp->mNextp = nodep; - mCurrentp->mPrevp = nodep; - } - else // at beginning of list - { - nodep->mPrevp = NULL; - nodep->mNextp = mCurrentp; - mHead.mNextp = nodep; - mCurrentp->mPrevp = nodep; - } - mCurrentp = mQueuep; - } - else // add to front of list - { - addNode(nodep); - } -} - - -// insert the data in front of mCurrentp -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::insertData(DATA_TYPE *data) -{ - if (!data) - { - llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - LLDoubleLinkedNode<DATA_TYPE> *node = new LLDoubleLinkedNode<DATA_TYPE>(data); - insertNode(node); - mCount++; -} - - -// if mCurrentp has a previous node then : -// * swaps mCurrentp with its previous -// * set mCurrentp to mQueuep -// otherwise does nothing -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithPrevious() -{ - if (mCurrentp) - { - if (mCurrentp->mPrevp) - { - // Pull mCurrentp out of list - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // mCurrentp was at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // Fix mCurrentp's pointers - mCurrentp->mNextp = mCurrentp->mPrevp; - mCurrentp->mPrevp = mCurrentp->mNextp->mPrevp; - mCurrentp->mNextp->mPrevp = mCurrentp; - - if (mCurrentp->mPrevp) - { - // Fix the backward pointer of mCurrentp's new previous - mCurrentp->mPrevp->mNextp = mCurrentp; - } - else // mCurrentp is now at beginning of list - { - mHead.mNextp = mCurrentp; - } - - // Set the list back to the way it was - mCurrentp = mQueuep; - } - } -} - - -// if mCurrentp has a next node then : -// * swaps mCurrentp with its next -// * set mCurrentp to mQueuep -// otherwise does nothing -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithNext() -{ - if (mCurrentp) - { - if (mCurrentp->mNextp) - { - // Pull mCurrentp out of list - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // mCurrentp was at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // Fix mCurrentp's pointers - mCurrentp->mPrevp = mCurrentp->mNextp; - mCurrentp->mNextp = mCurrentp->mPrevp->mNextp; - mCurrentp->mPrevp->mNextp = mCurrentp; - - if (mCurrentp->mNextp) - { - // Fix the back pointer of mCurrentp's new next - mCurrentp->mNextp->mPrevp = mCurrentp; - } - else // mCurrentp is now at end of list - { - mTail.mPrevp = mCurrentp; - } - - // Set the list back to the way it was - mCurrentp = mQueuep; - } - } -} - -// move mCurrentp to the front of the list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToFront() -{ - if (mCurrentp) - { - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - return; - } - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // add mCurrentp to beginning of list - mCurrentp->mNextp = mHead.mNextp; - mHead.mNextp->mPrevp = mCurrentp; // mHead.mNextp MUST be valid, - // or the list had only one node - // and we would have returned already - mCurrentp->mPrevp = NULL; - mHead.mNextp = mCurrentp; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } - -} - -// move mCurrentp to the end of the list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToEnd() -{ - if (mCurrentp) - { - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list and we're done - { - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - return; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // add mCurrentp to end of list - mCurrentp->mPrevp = mTail.mPrevp; - mTail.mPrevp->mNextp = mCurrentp; // mTail.mPrevp MUST be valid, - // or the list had only one node - // and we would have returned already - mCurrentp->mNextp = NULL; - mTail.mPrevp = mCurrentp; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second) ) -{ - mInsertBefore = insert_before; -} - - -// add data in front of the first node for which mInsertBefore(datap, node->mDatap) returns TRUE -// set mCurrentp to mQueuep -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::addDataSorted(DATA_TYPE *datap) -{ - // don't allow NULL to be passed to addData() - if (!datap) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addDataSorted()", 0); - } - - // has mInsertBefore not been set? - if (!mInsertBefore) - { - addData(datap); - return FALSE; - } - - // is the list empty? - if (!mHead.mNextp) - { - addData(datap); - return TRUE; - } - - // Note: this step has been added so that the behavior of LLDoubleLinkedList - // is as rigorous as the LLLinkedList class about adding duplicate nodes. - // Duplicate nodes can cause a problem when sorting if mInsertBefore(foo, foo) - // returns TRUE. However, if mInsertBefore(foo, foo) returns FALSE, then there - // shouldn't be any reason to exclude duplicate nodes (as we do here). - if (checkData(datap)) - { - return FALSE; - } - - mCurrentp = mHead.mNextp; - while (mCurrentp) - { - // check to see if datap is already in the list - if (datap == mCurrentp->mDatap) - { - return FALSE; - } - else if (mInsertBefore(datap, mCurrentp->mDatap)) - { - insertData(datap); - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - - addDataAtEnd(datap); - return TRUE; -} - - -// bubble-sort until sorted and return TRUE if anything was sorted -// leaves mQueuep pointing at last node that was swapped with its mNextp -// -// NOTE: if you find this function looping for really long times, then you -// probably need to check your implementation of mInsertBefore(a,b) and make -// sure it does not return TRUE when (a == b)! -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::bubbleSort() -{ - BOOL b_swapped = FALSE; - U32 count = 0; - while (lazyBubbleSort()) - { - b_swapped = TRUE; - if (count++ > 0x7FFFFFFF) - { - llwarning("LLDoubleLinkedList::bubbleSort() : too many passes...", 1); - llwarning(" make sure the mInsertBefore(a, b) does not return TRUE for a == b", 1); - break; - } - } - return b_swapped; -} - - -// do a single bubble-sort pass and return TRUE if anything was sorted -// leaves mQueuep pointing at last node that was swapped with its mNextp -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::lazyBubbleSort() -{ - // has mInsertBefore been set? - if (!mInsertBefore) - { - return FALSE; - } - - // is list empty? - mCurrentp = mHead.mNextp; - if (!mCurrentp) - { - return FALSE; - } - - BOOL b_swapped = FALSE; - - // the sort will exit after 0x7FFFFFFF nodes or the end of the list, whichever is first - S32 length = 0x7FFFFFFF; - S32 count = 0; - - while (mCurrentp && mCurrentp->mNextp && count<length) - { - if (mInsertBefore(mCurrentp->mNextp->mDatap, mCurrentp->mDatap)) - { - b_swapped = TRUE; - mQueuep = mCurrentp; - swapCurrentWithNext(); // sets mCurrentp to mQueuep - } - count++; - mCurrentp = mCurrentp->mNextp; - } - - return b_swapped; -} - - -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::pushState() -{ - if (mStateStackDepth < LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH) - { - *(mQueuepStack + mStateStackDepth) = mQueuep; - *(mCurrentpStack + mStateStackDepth) = mCurrentp; - mStateStackDepth++; - return TRUE; - } - return FALSE; -} - - -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::popState() -{ - if (mStateStackDepth > 0) - { - mStateStackDepth--; - mQueuep = *(mQueuepStack + mStateStackDepth); - mCurrentp = *(mCurrentpStack + mStateStackDepth); - return TRUE; - } - return FALSE; -} - - -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::clearStateStack() -{ - mStateStackDepth = 0; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// private members -////////////////////////////////////////////////////////////////////////////////////////// - -// add node to beginning of list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addNode(LLDoubleLinkedNode<DATA_TYPE> *nodep) -{ - // add the node to the front of the list - nodep->mPrevp = NULL; - nodep->mNextp = mHead.mNextp; - mHead.mNextp = nodep; - - // if there's something in the list, fix its back pointer - if (nodep->mNextp) - { - nodep->mNextp->mPrevp = nodep; - } - else // otherwise fix the tail node - { - mTail.mPrevp = nodep; - } - - mCurrentp = mQueuep; -} - - -// add node to end of list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node) -{ - // add the node to the end of the list - node->mNextp = NULL; - node->mPrevp = mTail.mPrevp; - mTail.mPrevp = node; - - // if there's something in the list, fix its back pointer - if (node->mPrevp) - { - node->mPrevp->mNextp = node; - } - else // otherwise fix the head node - { - mHead.mNextp = node; - } - - mCurrentp = mQueuep; -} - - -// randomly move nodes in the list for DEBUG (or Discordian) purposes -// sets mCurrentp and mQueuep to top of list -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::scramble() -{ - S32 random_number; - DATA_TYPE *datap = getFirstData(); - while(datap) - { - random_number = ll_rand(5); - - if (0 == random_number) - { - removeCurrentData(); - addData(datap); - } - else if (1 == random_number) - { - removeCurrentData(); - addDataAtEnd(datap); - } - else if (2 == random_number) - { - swapCurrentWithPrevious(); - } - else if (3 == random_number) - { - swapCurrentWithNext(); - } - datap = getNextData(); - } - mQueuep = mHead.mNextp; - mCurrentp = mQueuep; -} - -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::isEmpty() -{ - return (mCount == 0); -} - - -#endif diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index a0802c6adf..b6adb37eba 100755 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -29,6 +29,7 @@ #include "linden_common.h" #include "llapr.h" #include "apr_dso.h" +#include "llthreadlocalstorage.h" apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool. @@ -37,12 +38,15 @@ apr_thread_mutex_t *gCallStacksLogMutexp = NULL; const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool +bool gAPRInitialized = false; + void ll_init_apr() { + // Initialize APR and create the global pool + apr_initialize(); + if (!gAPRPoolp) { - // Initialize APR and create the global pool - apr_initialize(); apr_pool_create(&gAPRPoolp, NULL); // Initialize the logging mutex @@ -54,11 +58,21 @@ void ll_init_apr() { LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ; } + + LLThreadLocalPointerBase::initAllThreadLocalStorage(); + gAPRInitialized = true; } +bool ll_apr_is_initialized() +{ + return gAPRInitialized; +} + void ll_cleanup_apr() { + gAPRInitialized = false; + LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; if (gLogMutexp) @@ -77,6 +91,9 @@ void ll_cleanup_apr() apr_thread_mutex_destroy(gCallStacksLogMutexp); gCallStacksLogMutexp = NULL; } + + LLThreadLocalPointerBase::destroyAllThreadLocalStorage(); + if (gAPRPoolp) { apr_pool_destroy(gAPRPoolp); diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 752574c65d..e9b13c5919 100755 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -32,28 +32,34 @@ #if LL_LINUX || LL_SOLARIS #include <sys/param.h> // Need PATH_MAX in APR headers... #endif -#if LL_WINDOWS - // Limit Windows API to small and manageable set. - // If you get undefined symbols, find the appropriate - // Windows header file and include that in your .cpp file. - #define WIN32_LEAN_AND_MEAN - #include <winsock2.h> - #include <windows.h> -#endif #include <boost/noncopyable.hpp> - +#include "llwin32headerslean.h" #include "apr_thread_proc.h" #include "apr_thread_mutex.h" #include "apr_getopt.h" #include "apr_signal.h" #include "apr_atomic.h" + #include "llstring.h" extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; extern apr_thread_mutex_t* gCallStacksLogMutexp; struct apr_dso_handle_t; +/** + * @brief Function which appropriately logs error or remains quiet on + * APR_SUCCESS. + * @return Returns <code>true</code> if status is an error condition. + */ +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); +/// There's a whole other APR error-message function if you pass a DSO handle. +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle); + +void LL_COMMON_API ll_apr_assert_status(apr_status_t status); +void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle); + +extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool /** * @brief initialize the common apr constructs -- apr itself, the @@ -66,6 +72,9 @@ void LL_COMMON_API ll_init_apr(); */ void LL_COMMON_API ll_cleanup_apr(); +bool LL_COMMON_API ll_apr_is_initialized(); + + // //LL apr_pool //manage apr_pool_t, destroy allocated apr_pool in the destruction function. @@ -163,14 +172,17 @@ public: LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); }; ~LLAtomic32<Type>() {}; - operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); } + operator const Type() { return get(); } Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); } void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); } void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); } Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++ - Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise) + Type operator ++() { apr_atomic_inc32(&mData); return get(); } // ++Type + Type operator --(int) { const Type result(get()); apr_atomic_dec32(&mData); return result; } // Type-- + Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise) private: + const Type get() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); } apr_uint32_t mData; }; @@ -257,18 +269,5 @@ public: //******************************************************************************************************************************* }; -/** - * @brief Function which appropriately logs error or remains quiet on - * APR_SUCCESS. - * @return Returns <code>true</code> if status is an error condition. - */ -bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); -/// There's a whole other APR error-message function if you pass a DSO handle. -bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle); - -void LL_COMMON_API ll_apr_assert_status(apr_status_t status); -void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle); - -extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool #endif // LL_LLAPR_H diff --git a/indra/llcommon/llassoclist.h b/indra/llcommon/llassoclist.h deleted file mode 100755 index 2950504155..0000000000 --- a/indra/llcommon/llassoclist.h +++ /dev/null @@ -1,296 +0,0 @@ -/** - * @file llassoclist.h - * @brief LLAssocList class header file - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLASSOCLIST_H -#define LL_LLASSOCLIST_H - -//------------------------------------------------------------------------ -// LLAssocList is an associative list container class. -// -// The implementation is a single linked list. -// Both index and value objects are stored by value (not reference). -// If pointer values are specified for index and/or value, this -// container does NOT assume ownership of the referenced objects, -// and does NOT delete() them on removal or destruction of the container. -// -// Note that operations are generally not optimized, and may of them -// are O(n) complexity. -//------------------------------------------------------------------------ - -#include <iostream> - -template<class INDEX_TYPE, class VALUE_TYPE> -class LLAssocList -{ -private: - // internal list node type - class Node - { - public: - Node(const INDEX_TYPE &index, const VALUE_TYPE &value, Node *next) - { - mIndex = index; - mValue = value; - mNext = next; - } - ~Node() { } - INDEX_TYPE mIndex; - VALUE_TYPE mValue; - Node *mNext; - }; - - // head of the linked list - Node *mHead; - -public: - // Constructor - LLAssocList() - { - mHead = NULL; - } - - // Destructor - ~LLAssocList() - { - removeAll(); - } - - // Returns TRUE if list is empty. - BOOL isEmpty() - { - return (mHead == NULL); - } - - // Returns the number of items in the list. - U32 length() - { - U32 count = 0; - for ( Node *node = mHead; - node; - node = node->mNext ) - { - count++; - } - return count; - } - - // Removes item with the specified index. - BOOL remove( const INDEX_TYPE &index ) - { - if (!mHead) - return FALSE; - - if (mHead->mIndex == index) - { - Node *node = mHead; - mHead = mHead->mNext; - delete node; - return TRUE; - } - - for ( Node *prev = mHead; - prev->mNext; - prev = prev->mNext ) - { - if (prev->mNext->mIndex == index) - { - Node *node = prev->mNext; - prev->mNext = prev->mNext->mNext; - delete node; - return TRUE; - } - } - return FALSE; - } - - // Removes all items from the list. - void removeAll() - { - while ( mHead ) - { - Node *node = mHead; - mHead = mHead->mNext; - delete node; - } - } - - // Adds a new item to the head of the list, - // removing any existing item with same index. - void addToHead( const INDEX_TYPE &index, const VALUE_TYPE &value ) - { - remove(index); - Node *node = new Node(index, value, mHead); - mHead = node; - } - - // Adds a new item to the end of the list, - // removing any existing item with the same index. - void addToTail( const INDEX_TYPE &index, const VALUE_TYPE &value ) - { - remove(index); - Node *node = new Node(index, value, NULL); - if (!mHead) - { - mHead = node; - return; - } - for ( Node *prev=mHead; - prev; - prev=prev->mNext ) - { - if (!prev->mNext) - { - prev->mNext=node; - return; - } - } - } - - // Sets the value of a specified index. - // If index does not exist, a new value will be added only if - // 'addIfNotFound' is set to TRUE. - // Returns TRUE if successful. - BOOL setValue( const INDEX_TYPE &index, const VALUE_TYPE &value, BOOL addIfNotFound=FALSE ) - { - VALUE_TYPE *valueP = getValue(index); - if (valueP) - { - *valueP = value; - return TRUE; - } - if (!addIfNotFound) - return FALSE; - addToTail(index, value); - return TRUE; - } - - // Sets the ith value in the list. - // A new value will NOT be addded, if the ith value does not exist. - // Returns TRUE if successful. - BOOL setValueAt( U32 i, const VALUE_TYPE &value ) - { - VALUE_TYPE *valueP = getValueAt(i); - if (valueP) - { - *valueP = value; - return TRUE; - } - return FALSE; - } - - // Returns a pointer to the value for the specified index, - // or NULL if no item found. - VALUE_TYPE *getValue( const INDEX_TYPE &index ) - { - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (node->mIndex == index) - return &node->mValue; - } - return NULL; - } - - // Returns a pointer to the ith value in the list, or - // NULL if i is not valid. - VALUE_TYPE *getValueAt( U32 i ) - { - U32 count = 0; - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (count == i) - return &node->mValue; - count++; - } - return NULL; - } - - // Returns a pointer to the index for the specified index, - // or NULL if no item found. - INDEX_TYPE *getIndex( const INDEX_TYPE &index ) - { - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (node->mIndex == index) - return &node->mIndex; - } - return NULL; - } - - // Returns a pointer to the ith index in the list, or - // NULL if i is not valid. - INDEX_TYPE *getIndexAt( U32 i ) - { - U32 count = 0; - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (count == i) - return &node->mIndex; - count++; - } - return NULL; - } - - // Returns a pointer to the value for the specified index, - // or NULL if no item found. - VALUE_TYPE *operator[](const INDEX_TYPE &index) - { - return getValue(index); - } - - // Returns a pointer to the ith value in the list, or - // NULL if i is not valid. - VALUE_TYPE *operator[](U32 i) - { - return getValueAt(i); - } - - // Prints the list contents to the specified stream. - friend std::ostream &operator<<( std::ostream &os, LLAssocList &map ) - { - os << "{"; - for ( Node *node = map.mHead; - node; - node = node->mNext ) - { - os << "<" << node->mIndex << ", " << node->mValue << ">"; - if (node->mNext) - os << ", "; - } - os << "}"; - - return os; - } -}; - -#endif // LL_LLASSOCLIST_H diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 8be9e4f4de..c720df7555 100755 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -29,6 +29,7 @@ #include "llmemory.h" #include "llthread.h" +#include "lltrace.h" //static BOOL LLCommon::sAprInitialized = FALSE; @@ -44,15 +45,13 @@ void LLCommon::initClass() } LLTimer::initClass(); LLThreadSafeRefCount::initThreadSafeRefCount(); -// LLWorkerThread::initClass(); -// LLFrameCallbackManager::initClass(); + LLTrace::init(); } //static void LLCommon::cleanupClass() { -// LLFrameCallbackManager::cleanupClass(); -// LLWorkerThread::cleanupClass(); + LLTrace::cleanup(); LLThreadSafeRefCount::cleanupThreadSafeRefCount(); LLTimer::cleanupClass(); if (sAprInitialized) diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp index 87d79b1ee0..575fc4149e 100755 --- a/indra/llcommon/llcriticaldamp.cpp +++ b/indra/llcommon/llcriticaldamp.cpp @@ -27,18 +27,38 @@ #include "linden_common.h" #include "llcriticaldamp.h" +#include <algorithm> //----------------------------------------------------------------------------- // static members //----------------------------------------------------------------------------- -LLFrameTimer LLCriticalDamp::sInternalTimer; -std::map<F32, F32> LLCriticalDamp::sInterpolants; -F32 LLCriticalDamp::sTimeDelta; +LLFrameTimer LLSmoothInterpolation::sInternalTimer; +std::vector<LLSmoothInterpolation::Interpolant> LLSmoothInterpolation::sInterpolants; +F32 LLSmoothInterpolation::sTimeDelta; + +// helper functors +struct LLSmoothInterpolation::CompareTimeConstants +{ + bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a < b.mTimeScale; + } + + bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const + { + return a.mTimeScale < b; // bottom of a is higher than bottom of b + } + + bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b + } +}; //----------------------------------------------------------------------------- -// LLCriticalDamp() +// LLSmoothInterpolation() //----------------------------------------------------------------------------- -LLCriticalDamp::LLCriticalDamp() +LLSmoothInterpolation::LLSmoothInterpolation() { sTimeDelta = 0.f; } @@ -47,43 +67,54 @@ LLCriticalDamp::LLCriticalDamp() //----------------------------------------------------------------------------- // updateInterpolants() //----------------------------------------------------------------------------- -void LLCriticalDamp::updateInterpolants() +void LLSmoothInterpolation::updateInterpolants() { sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32(); - F32 time_constant; - - for (std::map<F32, F32>::iterator iter = sInterpolants.begin(); - iter != sInterpolants.end(); iter++) + for (S32 i = 0; i < sInterpolants.size(); i++) { - time_constant = iter->first; - F32 new_interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant); - new_interpolant = llclamp(new_interpolant, 0.f, 1.f); - sInterpolants[time_constant] = new_interpolant; + Interpolant& interp = sInterpolants[i]; + interp.mInterpolant = calcInterpolant(interp.mTimeScale); } } //----------------------------------------------------------------------------- // getInterpolant() //----------------------------------------------------------------------------- -F32 LLCriticalDamp::getInterpolant(const F32 time_constant, BOOL use_cache) +F32 LLSmoothInterpolation::getInterpolant(LLUnit<F32, LLUnits::Seconds> time_constant, bool use_cache) { if (time_constant == 0.f) { return 1.f; } - if (use_cache && sInterpolants.count(time_constant)) + if (use_cache) { - return sInterpolants[time_constant]; + interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants()); + if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant) + { + return find_it->mInterpolant; + } + else + { + Interpolant interp; + interp.mTimeScale = time_constant.value(); + interp.mInterpolant = calcInterpolant(time_constant.value()); + sInterpolants.insert(find_it, interp); + return interp.mInterpolant; + } } - - F32 interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant); - interpolant = llclamp(interpolant, 0.f, 1.f); - if (use_cache) + else { - sInterpolants[time_constant] = interpolant; + return calcInterpolant(time_constant.value()); + } +} - return interpolant; +//----------------------------------------------------------------------------- +// calcInterpolant() +//----------------------------------------------------------------------------- +F32 LLSmoothInterpolation::calcInterpolant(F32 time_constant) +{ + return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f); } diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index 52f052ae25..e174643cd0 100755 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -28,26 +28,46 @@ #ifndef LL_LLCRITICALDAMP_H #define LL_LLCRITICALDAMP_H -#include <map> +#include <vector> #include "llframetimer.h" +#include "llunit.h" -class LL_COMMON_API LLCriticalDamp +class LL_COMMON_API LLSmoothInterpolation { public: - LLCriticalDamp(); + LLSmoothInterpolation(); // MANIPULATORS static void updateInterpolants(); // ACCESSORS - static F32 getInterpolant(const F32 time_constant, BOOL use_cache = TRUE); + static F32 getInterpolant(LLUnit<F32, LLUnits::Seconds> time_constant, bool use_cache = true); -protected: + template<typename T> + static T lerp(T a, T b, LLUnit<F32, LLUnits::Seconds> time_constant, bool use_cache = true) + { + F32 interpolant = getInterpolant(time_constant, use_cache); + return ((a * (1.f - interpolant)) + + (b * interpolant)); + } + +protected: + static F32 calcInterpolant(F32 time_constant); + + struct CompareTimeConstants; static LLFrameTimer sInternalTimer; // frame timer for calculating deltas - static std::map<F32, F32> sInterpolants; + struct Interpolant + { + F32 mTimeScale; + F32 mInterpolant; + }; + typedef std::vector<Interpolant> interpolant_vec_t; + static interpolant_vec_t sInterpolants; static F32 sTimeDelta; }; +typedef LLSmoothInterpolation LLCriticalDamp; + #endif // LL_LLCRITICALDAMP_H diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 030ef6a3c7..7892269e35 100755 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -39,6 +39,7 @@ #include "lltimer.h" #include "llstring.h" +#include "llfasttimer.h" static const F64 DATE_EPOCH = 0.0; @@ -48,18 +49,15 @@ static const F64 LL_APR_USEC_PER_SEC = 1000000.0; LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH) -{ -} +{} LLDate::LLDate(const LLDate& date) : mSecondsSinceEpoch(date.mSecondsSinceEpoch) -{ -} +{} -LLDate::LLDate(F64 seconds_since_epoch) : - mSecondsSinceEpoch(seconds_since_epoch) -{ -} +LLDate::LLDate(LLUnit<F64, LLUnits::Seconds> seconds_since_epoch) : + mSecondsSinceEpoch(seconds_since_epoch.value()) +{} LLDate::LLDate(const std::string& iso8601_date) { diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 7ff8b550ad..1067ac5280 100755 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -33,6 +33,7 @@ #include <string> #include "stdtypes.h" +#include "llunit.h" /** * @class LLDate @@ -56,9 +57,9 @@ public: /** * @brief Construct a date from a seconds since epoch value. * - * @pararm seconds_since_epoch The number of seconds since UTC epoch. + * @param seconds_since_epoch The number of seconds since UTC epoch. */ - LLDate(F64 seconds_since_epoch); + LLDate(LLUnit<F64, LLUnits::Seconds> seconds_since_epoch); /** * @brief Construct a date from a string representation diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index 5a4b8325f4..d57b9dccff 100755 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -244,5 +244,8 @@ inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs) rhs = tmp; } +#define LL_GLUE_IMPL(x, y) x##y +#define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y) + #endif // LL_LLDEFS_H diff --git a/indra/llcommon/lldeleteutils.h b/indra/llcommon/lldeleteutils.h index f250dc3028..f250dc3028 100755..100644 --- a/indra/llcommon/lldeleteutils.h +++ b/indra/llcommon/lldeleteutils.h diff --git a/indra/llcommon/lldepthstack.h b/indra/llcommon/lldepthstack.h index d9db54efc7..ac435a30fa 100755 --- a/indra/llcommon/lldepthstack.h +++ b/indra/llcommon/lldepthstack.h @@ -27,17 +27,20 @@ #ifndef LL_LLDEPTHSTACK_H #define LL_LLDEPTHSTACK_H -#include "linked_lists.h" +#include "llstl.h" template <class DATA_TYPE> class LLDepthStack { private: - LLLinkedList<DATA_TYPE> mStack; + std::deque<DATA_TYPE*> mStack; U32 mCurrentDepth; U32 mMaxDepth; public: - LLDepthStack() : mCurrentDepth(0), mMaxDepth(0) {} + LLDepthStack() + : mCurrentDepth(0), mMaxDepth(0) + {} + ~LLDepthStack() {} void setDepth(U32 depth) @@ -54,24 +57,27 @@ public: { if (mCurrentDepth < mMaxDepth) { - mStack.addData(data); + mStack.push_back(data); mCurrentDepth++; } else { // the last item falls off stack and is deleted - mStack.getLastData(); - mStack.deleteCurrentData(); - mStack.addData(data); + if (!mStack.empty()) + { + mStack.pop_front(); + } + mStack.push_back(data); } } DATA_TYPE *pop() { - DATA_TYPE *tempp = mStack.getFirstData(); - if (tempp) + DATA_TYPE *tempp = NULL; + if (!mStack.empty()) { - mStack.removeCurrentData(); + tempp = mStack.back(); + mStack.pop_back(); mCurrentDepth--; } return tempp; @@ -79,20 +85,20 @@ public: DATA_TYPE *check() { - DATA_TYPE *tempp = mStack.getFirstData(); - return tempp; + return mStack.empty() ? NULL : mStack.back(); } void deleteAllData() { mCurrentDepth = 0; - mStack.deleteAllData(); + std::for_each(mStack.begin(), mStack.end(), DeletePointer()); + mStack.clear(); } void removeAllNodes() { mCurrentDepth = 0; - mStack.removeAllNodes(); + mStack.clear(); } }; diff --git a/indra/llcommon/lldlinked.h b/indra/llcommon/lldlinked.h deleted file mode 100755 index 3f7c197be7..0000000000 --- a/indra/llcommon/lldlinked.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file lldlinked.h - * @brief Declaration of the LLDLinked class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLDLINKED_H -#define LL_LLDLINKED_H - -template <class Type> class LLDLinked -{ - LLDLinked* mNextp; - LLDLinked* mPrevp; -public: - - Type* getNext() { return (Type*)mNextp; } - Type* getPrev() { return (Type*)mPrevp; } - Type* getFirst() { return (Type*)mNextp; } - - void init() - { - mNextp = mPrevp = NULL; - } - - void unlink() - { - if (mPrevp) mPrevp->mNextp = mNextp; - if (mNextp) mNextp->mPrevp = mPrevp; - } - - LLDLinked() { mNextp = mPrevp = NULL; } - virtual ~LLDLinked() { unlink(); } - - virtual void deleteAll() - { - Type *curp = getFirst(); - while(curp) - { - Type *nextp = curp->getNext(); - curp->unlink(); - delete curp; - curp = nextp; - } - } - - void relink(Type &after) - { - LLDLinked *afterp = (LLDLinked*)&after; - afterp->mPrevp = this; - mNextp = afterp; - } - - virtual void append(Type& after) - { - LLDLinked *afterp = (LLDLinked*)&after; - afterp->mPrevp = this; - afterp->mNextp = mNextp; - if (mNextp) mNextp->mPrevp = afterp; - mNextp = afterp; - } - - virtual void insert(Type& before) - { - LLDLinked *beforep = (LLDLinked*)&before; - beforep->mNextp = this; - beforep->mPrevp = mPrevp; - if (mPrevp) mPrevp->mNextp = beforep; - mPrevp = beforep; - } - - virtual void put(Type& obj) { append(obj); } -}; - -#endif diff --git a/indra/llcommon/lldqueueptr.h b/indra/llcommon/lldqueueptr.h deleted file mode 100755 index 9fe08191e1..0000000000 --- a/indra/llcommon/lldqueueptr.h +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @file lldqueueptr.h - * @brief LLDynamicQueuePtr declaration - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLDQUEUEPTR_H -#define LL_LLDQUEUEPTR_H - -template <class Type> -class LLDynamicQueuePtr -{ -public: - enum - { - OKAY = 0, - FAIL = -1 - }; - - LLDynamicQueuePtr(const S32 size=8); - ~LLDynamicQueuePtr(); - - void init(); - void destroy(); - void reset(); - void reallocate(U32 newsize); - - // ACCESSORS - const Type& get(const S32 index) const; // no bounds checking - Type& get(const S32 index); // no bounds checking - const Type& operator [] (const S32 index) const { return get(index); } - Type& operator [] (const S32 index) { return get(index); } - S32 find(const Type &obj) const; - - S32 count() const { return (mLastObj >= mFirstObj ? mLastObj - mFirstObj : mLastObj + mMaxObj - mFirstObj); } - S32 getMax() const { return mMaxObj; } - S32 getFirst() const { return mFirstObj; } - S32 getLast () const { return mLastObj; } - - // MANIPULATE - S32 push(const Type &obj); // add to end of Queue, returns index from start - S32 pull( Type &obj); // pull from Queue, returns index from start - - S32 remove (S32 index); // remove by index - S32 removeObj(const Type &obj); // remove by object - -protected: - S32 mFirstObj, mLastObj, mMaxObj; - Type* mMemory; - -public: - - void print() - { - /* - Convert this to llinfos if it's intended to be used - djs 08/30/02 - - printf("Printing from %d to %d (of %d): ",mFirstObj, mLastObj, mMaxObj); - - if (mFirstObj <= mLastObj) - { - for (S32 i=mFirstObj;i<mLastObj;i++) - { - printf("%d ",mMemory[i]); - } - } - else - { - for (S32 i=mFirstObj;i<mMaxObj;i++) - { - printf("%d ",mMemory[i]); - } - for (i=0;i<mLastObj;i++) - { - printf("%d ",mMemory[i]); - } - } - printf("\n"); - */ - } - -}; - - -//-------------------------------------------------------- -// LLDynamicQueuePtrPtr implementation -//-------------------------------------------------------- - - -template <class Type> -inline LLDynamicQueuePtr<Type>::LLDynamicQueuePtr(const S32 size) -{ - init(); - reallocate(size); -} - -template <class Type> -inline LLDynamicQueuePtr<Type>::~LLDynamicQueuePtr() -{ - destroy(); -} - -template <class Type> -inline void LLDynamicQueuePtr<Type>::init() -{ - mFirstObj = 0; - mLastObj = 0; - mMaxObj = 0; - mMemory = NULL; -} - -template <class Type> -inline void LLDynamicQueuePtr<Type>::reallocate(U32 newsize) -{ - if (newsize) - { - if (mFirstObj > mLastObj && newsize > mMaxObj) - { - Type* new_memory = new Type[newsize]; - - llassert(new_memory); - - S32 _count = count(); - S32 i, m = 0; - for (i=mFirstObj; i < mMaxObj; i++) - { - new_memory[m++] = mMemory[i]; - } - for (i=0; i <=mLastObj; i++) - { - new_memory[m++] = mMemory[i]; - } - - delete[] mMemory; - mMemory = new_memory; - - mFirstObj = 0; - mLastObj = _count; - } - else - { - Type* new_memory = new Type[newsize]; - - llassert(new_memory); - - S32 i, m = 0; - for (i=0; i < mLastObj; i++) - { - new_memory[m++] = mMemory[i]; - } - delete[] mMemory; - mMemory = new_memory; - } - } - else if (mMemory) - { - delete[] mMemory; - mMemory = NULL; - } - - mMaxObj = newsize; -} - -template <class Type> -inline void LLDynamicQueuePtr<Type>::destroy() -{ - reset(); - delete[] mMemory; - mMemory = NULL; -} - - -template <class Type> -void LLDynamicQueuePtr<Type>::reset() -{ - for (S32 i=0; i < mMaxObj; i++) - { - get(i) = NULL; // unrefs for pointers - } - - mFirstObj = 0; - mLastObj = 0; -} - - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::find(const Type &obj) const -{ - S32 i; - if (mFirstObj <= mLastObj) - { - for ( i = mFirstObj; i < mLastObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - } - else - { - for ( i = mFirstObj; i < mMaxObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - for ( i = 0; i < mLastObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - } - - return FAIL; -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::remove(S32 i) -{ - if (mFirstObj > mLastObj) - { - if (i >= mFirstObj && i < mMaxObj) - { - while( i > mFirstObj) - { - mMemory[i] = mMemory[i-1]; - i--; - } - mMemory[mFirstObj] = NULL; - mFirstObj++; - if (mFirstObj >= mMaxObj) mFirstObj = 0; - - return count(); - } - else if (i < mLastObj && i >= 0) - { - while(i < mLastObj) - { - mMemory[i] = mMemory[i+1]; - i++; - } - mMemory[mLastObj] = NULL; - mLastObj--; - if (mLastObj < 0) mLastObj = mMaxObj-1; - - return count(); - } - } - else if (i <= mLastObj && i >= mFirstObj) - { - while(i < mLastObj) - { - mMemory[i] = mMemory[i+1]; - i++; - } - mMemory[mLastObj] = NULL; - mLastObj--; - if (mLastObj < 0) mLastObj = mMaxObj-1; - - return count(); - } - - - return FAIL; -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::removeObj(const Type& obj) -{ - S32 ind = find(obj); - if (ind >= 0) - { - return remove(ind); - } - return FAIL; -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::push(const Type &obj) -{ - if (mMaxObj - count() <= 1) - { - reallocate(mMaxObj * 2); - } - - mMemory[mLastObj++] = obj; - - if (mLastObj >= mMaxObj) - { - mLastObj = 0; - } - - return count(); -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::pull(Type &obj) -{ - obj = NULL; - - if (count() < 1) return -1; - - obj = mMemory[mFirstObj]; - mMemory[mFirstObj] = NULL; - - mFirstObj++; - - if (mFirstObj >= mMaxObj) - { - mFirstObj = 0; - } - - return count(); -} - -template <class Type> -inline const Type& LLDynamicQueuePtr<Type>::get(const S32 i) const -{ - return mMemory[i]; -} - -template <class Type> -inline Type& LLDynamicQueuePtr<Type>::get(const S32 i) -{ - return mMemory[i]; -} - - -#endif // LL_LLDQUEUEPTR_H diff --git a/indra/llcommon/llenum.h b/indra/llcommon/llenum.h deleted file mode 100755 index f57b2bc0b5..0000000000 --- a/indra/llcommon/llenum.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file llenum.h - * @author Tom Yedwab - * @brief Utility class for storing enum value <-> string lookup. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLENUM_H -#define LL_LLENUM_H - -class LLEnum -{ -public: - typedef std::pair<const std::string, const U32> enum_t; - enum - { - UNDEFINED = 0xffffffff, - }; - - LLEnum(const enum_t values_array[], const U32 length) - { - for (U32 i=0; i<length; ++i) - { - mEnumMap.insert(values_array[i]); - if (values_array[i].second >= mEnumArray.size()) - { - mEnumArray.resize(values_array[i].second+1); - } - mEnumArray[values_array[i].second] = values_array[i].first; - } - } - - U32 operator[](std::string str) - { - std::map<const std::string, const U32>::iterator itor; - itor = mEnumMap.find(str); - if (itor != mEnumMap.end()) - { - return itor->second; - } - return UNDEFINED; - } - - const std::string operator[](U32 index) - { - if (index < mEnumArray.size()) - { - return mEnumArray[index]; - } - return ""; - } - -private: - std::map<const std::string, const U32> mEnumMap; - std::vector<std::string> mEnumArray; -}; - -#endif // LL_LLENUM_H diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 37cee579cd..50c95339e4 100755 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -29,6 +29,7 @@ #define LL_LLERRORLEGACY_H #include "llpreprocessor.h" +#include <boost/static_assert.hpp> /* LEGACY -- DO NOT USE THIS STUFF ANYMORE @@ -111,6 +112,14 @@ const int LL_ERR_PRICE_MISMATCH = -23018; #define llverify(func) do {if (func) {}} while(0) #endif +#ifdef LL_WINDOWS +#define LL_STATIC_ASSERT(func, msg) static_assert(func, msg) +#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) static_assert(false, msg) +#else +#define LL_STATIC_ASSERT(func, msg) BOOST_STATIC_ASSERT(func) +#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && false); +#endif + // handy compile-time assert - enforce those template parameters! #define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */ //XXX: used in two places in llcommon/llskipmap.h diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 0855180dcd..1c928b3db8 100755 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -41,7 +41,6 @@ #include <algorithm> // std headers #include <typeinfo> -#include <cassert> #include <cmath> #include <cctype> // external library headers diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 024fdd1b4d..60c451b137 100755 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -32,8 +32,13 @@ #include "llsingleton.h" #include "lltreeiterators.h" #include "llsdserialize.h" +#include "llunit.h" +#include "llsd.h" +#include "lltracerecording.h" +#include "lltracethreadrecorder.h" #include <boost/bind.hpp> +#include <queue> #if LL_WINDOWS @@ -49,37 +54,36 @@ #error "architecture not supported" #endif +namespace LLTrace +{ + ////////////////////////////////////////////////////////////////////////////// // statics -S32 LLFastTimer::sCurFrameIndex = -1; -S32 LLFastTimer::sLastFrameIndex = -1; -U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64(); -bool LLFastTimer::sPauseHistory = 0; -bool LLFastTimer::sResetHistory = 0; -LLFastTimer::CurTimerData LLFastTimer::sCurTimerData; -BOOL LLFastTimer::sLog = FALSE; -std::string LLFastTimer::sLogName = ""; -BOOL LLFastTimer::sMetricLog = FALSE; -LLMutex* LLFastTimer::sLogLock = NULL; -std::queue<LLSD> LLFastTimer::sLogQueue; +bool TimeBlock::sLog = false; +std::string TimeBlock::sLogName = ""; +bool TimeBlock::sMetricLog = false; #if LL_LINUX || LL_SOLARIS -U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution +U64 TimeBlock::sClockResolution = 1000000000; // Nanosecond resolution #else -U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution +U64 TimeBlock::sClockResolution = 1000000; // Microsecond resolution #endif +static LLMutex* sLogLock = NULL; +static std::queue<LLSD> sLogQueue; + + // FIXME: move these declarations to the relevant modules // helper functions -typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t; +typedef LLTreeDFSPostIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_bottom_up_iterator_t; -static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id) +static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(TimeBlock& id) { return timer_tree_bottom_up_iterator_t(&id, - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); + boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1), + boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1)); } static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up() @@ -87,14 +91,14 @@ static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up() return timer_tree_bottom_up_iterator_t(); } -typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t; +typedef LLTreeDFSIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_dfs_iterator_t; -static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) +static timer_tree_dfs_iterator_t begin_timer_tree(TimeBlock& id) { return timer_tree_dfs_iterator_t(&id, - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); + boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1), + boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1)); } static timer_tree_dfs_iterator_t end_timer_tree() @@ -102,90 +106,48 @@ static timer_tree_dfs_iterator_t end_timer_tree() return timer_tree_dfs_iterator_t(); } -// factory class that creates NamedTimers via static DeclareTimer objects -class NamedTimerFactory : public LLSingleton<NamedTimerFactory> -{ -public: - NamedTimerFactory() - : mTimerRoot(NULL) - {} - /*virtual */ void initSingleton() +// sort child timers by name +struct SortTimerByName +{ + bool operator()(const TimeBlock* i1, const TimeBlock* i2) { - mTimerRoot = new LLFastTimer::NamedTimer("root"); - mRootFrameState.setNamedTimer(mTimerRoot); - mTimerRoot->setFrameState(&mRootFrameState); - mTimerRoot->mParent = mTimerRoot; - mTimerRoot->setCollapsed(false); - mRootFrameState.mParent = &mRootFrameState; + return i1->getName() < i2->getName(); } +}; - ~NamedTimerFactory() +TimeBlock& TimeBlock::getRootTimeBlock() { - std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer()); - - delete mTimerRoot; + static TimeBlock root_timer("root", NULL); + return root_timer; } - LLFastTimer::NamedTimer& createNamedTimer(const std::string& name, LLFastTimer::FrameState* state) +void TimeBlock::pushLog(LLSD log) { - LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name); - timer->setFrameState(state); - timer->setParent(mTimerRoot); - mTimers.insert(std::make_pair(name, timer)); + LLMutexLock lock(sLogLock); - return *timer; + sLogQueue.push(log); } - LLFastTimer::NamedTimer* getTimerByName(const std::string& name) +void TimeBlock::setLogLock(LLMutex* lock) { - timer_map_t::iterator found_it = mTimers.find(name); - if (found_it != mTimers.end()) - { - return found_it->second; - } - return NULL; + sLogLock = lock; } - LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; } - - typedef std::multimap<std::string, LLFastTimer::NamedTimer*> timer_map_t; - timer_map_t::iterator beginTimers() { return mTimers.begin(); } - timer_map_t::iterator endTimers() { return mTimers.end(); } - S32 timerCount() { return mTimers.size(); } - -private: - timer_map_t mTimers; - - LLFastTimer::NamedTimer* mTimerRoot; - LLFastTimer::FrameState mRootFrameState; -}; - -LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open ) -: mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState)) -{ - mTimer.setCollapsed(!open); -} - -LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name) -: mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState)) -{ -} //static #if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) -U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer +U64 TimeBlock::countsPerSecond() { - return sClockResolution >> 8; + return sClockResolution; } #else // windows or x86-mac or x86-linux or x86-solaris -U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer +U64 TimeBlock::countsPerSecond() { #if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz - static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0); - - // we drop the low-order byte in our timers, so report a lower frequency + static LLUnit<U64, LLUnits::Hertz> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency(); + return sCPUClockFrequency.value(); #else // If we're not using RDTSC, each fasttimer tick is just a performance counter tick. // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency()) @@ -197,270 +159,207 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency); firstcall = false; } + return sCPUClockFrequency.value(); #endif - return sCPUClockFrequency >> 8; } #endif -LLFastTimer::FrameState::FrameState() -: mActiveCount(0), - mCalls(0), - mSelfTimeCounter(0), - mParent(NULL), - mLastCaller(NULL), - mMoveUpTree(false) -{} - - -LLFastTimer::NamedTimer::NamedTimer(const std::string& name) -: mName(name), - mCollapsed(true), - mParent(NULL), - mTotalTimeCounter(0), - mCountAverage(0), - mCallAverage(0), - mNeedsSorting(false), - mFrameState(NULL) +TimeBlock::TimeBlock(const char* name, TimeBlock* parent) +: TraceType<TimeBlockAccumulator>(name) { - mCountHistory = new U32[HISTORY_NUM]; - memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM); - mCallHistory = new U32[HISTORY_NUM]; - memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM); } -LLFastTimer::NamedTimer::~NamedTimer() +TimeBlockTreeNode& TimeBlock::getTreeNode() const { - delete[] mCountHistory; - delete[] mCallHistory; + TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex()); + llassert(nodep); + return *nodep; } -std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx) -{ - F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond(); - if (history_idx < 0) - { - // by default, show average number of call - return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getCountAverage() * ms_multiplier), (S32)getCallAverage()); - } - else - { - return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx)); - } -} -void LLFastTimer::NamedTimer::setParent(NamedTimer* parent) +void TimeBlock::bootstrapTimerTree() { - llassert_always(parent != this); - llassert_always(parent != NULL); - - if (mParent) - { - // subtract our accumulated from previous parent - for (S32 i = 0; i < HISTORY_NUM; i++) + for (LLInstanceTracker<TimeBlock>::instance_iter begin_it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(), it = begin_it; + it != end_it; + ++it) { - mParent->mCountHistory[i] -= mCountHistory[i]; - } + TimeBlock& timer = *it; + if (&timer == &TimeBlock::getRootTimeBlock()) continue; - // subtract average timing from previous parent - mParent->mCountAverage -= mCountAverage; - - std::vector<NamedTimer*>& children = mParent->getChildren(); - std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this); - if (found_it != children.end()) + // bootstrap tree construction by attaching to last timer to be on stack + // when this timer was called + if (timer.getParent() == &TimeBlock::getRootTimeBlock()) { - children.erase(found_it); - } - } + TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator(); - mParent = parent; - if (parent) + if (accumulator->mLastCaller) { - getFrameState().mParent = &parent->getFrameState(); - parent->getChildren().push_back(this); - parent->mNeedsSorting = true; + timer.setParent(accumulator->mLastCaller); + accumulator->mParent = accumulator->mLastCaller; } + // no need to push up tree on first use, flag can be set spuriously + accumulator->mMoveUpTree = false; } - -S32 LLFastTimer::NamedTimer::getDepth() -{ - S32 depth = 0; - NamedTimer* timerp = mParent; - while(timerp) - { - depth++; - if (timerp->getParent() == timerp) break; - timerp = timerp->mParent; } - return depth; -} - -// static -void LLFastTimer::NamedTimer::processTimes() -{ - if (sCurFrameIndex < 0) return; - - buildHierarchy(); - accumulateTimings(); } -// sort child timers by name -struct SortTimerByName +// bump timers up tree if they have been flagged as being in the wrong place +// do this in a bottom up order to promote descendants first before promoting ancestors +// this preserves partial order derived from current frame's observations +void TimeBlock::incrementalUpdateTimerTree() { - bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2) + for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimeBlock()); + it != end_timer_tree_bottom_up(); + ++it) { - return i1->getName() < i2->getName(); - } -}; - -//static -void LLFastTimer::NamedTimer::buildHierarchy() -{ - if (sCurFrameIndex < 0 ) return; + TimeBlock* timerp = *it; - // 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()) + // sort timers by time last called, so call graph makes sense + TimeBlockTreeNode& tree_node = timerp->getTreeNode(); + if (tree_node.mNeedsSorting) { - timer.setParent(timer.getFrameState().mLastCaller->mTimer); - // no need to push up tree on first use, flag can be set spuriously - timer.getFrameState().mMoveUpTree = false; - } - } + std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName()); } - // 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 != &TimeBlock::getRootTimeBlock()) + { + TimeBlockAccumulator* accumulator = timerp->getPrimaryAccumulator(); - if (timerp->getFrameState().mMoveUpTree) + if (accumulator->mMoveUpTree) { - // since ancestors have already been visited, reparenting won't affect tree traversal + // since ancestors have already been visited, re-parenting won't affect tree traversal //step up tree, bringing our descendants with us LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL; timerp->setParent(timerp->getParent()->getParent()); - timerp->getFrameState().mMoveUpTree = false; + accumulator->mParent = timerp->getParent(); + accumulator->mMoveUpTree = false; // don't bubble up any ancestors until descendants are done bubbling up + // as ancestors may call this timer only on certain paths, so we want to resolve + // child-most block locations before their parents it.skipAncestors(); } } + } +} - // sort timers by time last called, so call graph makes sense - for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); - it != end_timer_tree(); - ++it) + +void TimeBlock::updateTimes() { - NamedTimer* timerp = (*it); - if (timerp->mNeedsSorting) + U64 cur_time = getCPUClockCount64(); + + // walk up stack of active timers and accumulate current time while leaving timing structures active + BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance(); + BlockTimer* cur_timer = stack_record->mActiveTimer; + TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator(); + + while(cur_timer + && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self { - std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName()); - } - timerp->mNeedsSorting = false; + U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; + accumulator->mTotalTimeCounter += cumulative_time_delta + - (accumulator->mTotalTimeCounter + - cur_timer->mBlockStartTotalTimeCounter); + accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime; + stack_record->mChildTime = 0; + + cur_timer->mStartTime = cur_time; + cur_timer->mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter; + + stack_record = &cur_timer->mParentTimerData; + accumulator = stack_record->mTimeBlock->getPrimaryAccumulator(); + cur_timer = stack_record->mActiveTimer; + + stack_record->mChildTime += cumulative_time_delta; } } +static LLFastTimer::DeclareTimer FTM_PROCESS_TIMES("Process FastTimer Times"); + +// not thread safe, so only call on main thread //static -void LLFastTimer::NamedTimer::accumulateTimings() +void TimeBlock::processTimes() { - U32 cur_time = getCPUClockCount32(); + LLFastTimer _(FTM_PROCESS_TIMES); + get_clock_count(); // good place to calculate clock frequency - // walk up stack of active timers and accumulate current time while leaving timing structures active - LLFastTimer* cur_timer = sCurTimerData.mCurTimer; - // root defined by parent pointing to self - CurTimerData* cur_data = &sCurTimerData; - while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer) - { - U32 cumulative_time_delta = cur_time - cur_timer->mStartTime; - U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime; - cur_data->mChildTime = 0; - cur_timer->mFrameState->mSelfTimeCounter += self_time_delta; - cur_timer->mStartTime = cur_time; + // set up initial tree + bootstrapTimerTree(); - cur_data = &cur_timer->mLastTimerData; - cur_data->mChildTime += cumulative_time_delta; + incrementalUpdateTimerTree(); - cur_timer = cur_timer->mLastTimerData.mCurTimer; - } + updateTimes(); - // traverse tree in DFS post order, or bottom up - for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer()); - it != end_timer_tree_bottom_up(); + // reset for next frame + for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), + end_it = LLInstanceTracker<TimeBlock>::endInstances(); + it != end_it; ++it) { - NamedTimer* timerp = (*it); - timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter; - for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it) + TimeBlock& timer = *it; + TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator(); + + accumulator->mLastCaller = NULL; + accumulator->mMoveUpTree = false; + } +} + +std::vector<TimeBlock*>::iterator TimeBlock::beginChildren() { - timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter; + return getTreeNode().mChildren.begin(); } - S32 cur_frame = sCurFrameIndex; - if (cur_frame >= 0) +std::vector<TimeBlock*>::iterator TimeBlock::endChildren() { - // update timer history - int hidx = cur_frame % HISTORY_NUM; + return getTreeNode().mChildren.end(); +} - 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); - } - } +std::vector<TimeBlock*>& TimeBlock::getChildren() +{ + return getTreeNode().mChildren; } // static -void LLFastTimer::NamedTimer::resetFrame() +void TimeBlock::logStats() { + // get ready for next frame if (sLog) { //output current frame counts to performance log static S32 call_count = 0; if (call_count % 100 == 0) { - LL_DEBUGS("FastTimers") << "countsPerSecond (32 bit): " << countsPerSecond() << LL_ENDL; - LL_DEBUGS("FastTimers") << "get_clock_count (64 bit): " << get_clock_count() << llendl; + LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL; LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL; LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL; LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL; - LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << LL_ENDL; + LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64()) / (LLUnit<F64, LLUnits::Hertz>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL; } call_count++; - F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency - - F64 total_time = 0; + LLUnit<F64, LLUnits::Seconds> total_time(0); LLSD sd; { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), + end_it = LLInstanceTracker<TimeBlock>::endInstances(); + it != end_it; + ++it) { - NamedTimer& timer = *it; - FrameState& info = timer.getFrameState(); - sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq); - sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls; + TimeBlock& timer = *it; + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value()); + sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount())); // computing total time here because getting the root timer's getCountHistory // doesn't work correctly on the first frame - total_time = total_time + info.mSelfTimeCounter * iclock_freq; + total_time += frame_recording.getLastRecording().getSum(timer); } } - sd["Total"]["Time"] = (LLSD::Real) total_time; + sd["Total"]["Time"] = (LLSD::Real) total_time.value(); sd["Total"]["Calls"] = (LLSD::Integer) 1; { @@ -469,168 +368,44 @@ void LLFastTimer::NamedTimer::resetFrame() } } - // reset for next frame - for (instance_iter it = beginInstances(); it != endInstances(); ++it) - { - NamedTimer& timer = *it; - - FrameState& info = timer.getFrameState(); - info.mSelfTimeCounter = 0; - info.mCalls = 0; - info.mLastCaller = NULL; - info.mMoveUpTree = false; - // update parent pointer in timer state struct - if (timer.mParent) - { - info.mParent = &timer.mParent->getFrameState(); - } - } } //static -void LLFastTimer::NamedTimer::reset() -{ - resetFrame(); // reset frame data - - // walk up stack of active timers and reset start times to current time - // effectively zeroing out any accumulated time - U32 cur_time = getCPUClockCount32(); - - // root defined by parent pointing to self - CurTimerData* cur_data = &sCurTimerData; - LLFastTimer* cur_timer = cur_data->mCurTimer; - while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer) - { - cur_timer->mStartTime = cur_time; - cur_data->mChildTime = 0; - - cur_data = &cur_timer->mLastTimerData; - cur_timer = cur_data->mCurTimer; - } - - // reset all history +void TimeBlock::dumpCurTimes() { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) - { - NamedTimer& timer = *it; - if (&timer != NamedTimerFactory::instance().getRootTimer()) - { - timer.setParent(NamedTimerFactory::instance().getRootTimer()); - } - - timer.mCountAverage = 0; - timer.mCallAverage = 0; - memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM); - memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM); - } - } - - sLastFrameIndex = 0; - sCurFrameIndex = 0; -} - -U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const -{ - S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; - return mCountHistory[history_idx]; -} - -U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const -{ - S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; - return mCallHistory[history_idx]; -} - -LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const -{ - return *mFrameState; -} - -std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren() -{ - return mChildren.begin(); -} - -std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren() -{ - return mChildren.end(); -} - -std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren() -{ - return mChildren; -} - -//static -LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer() -{ - return *NamedTimerFactory::instance().getRootTimer(); -} - -//static -void LLFastTimer::nextFrame() -{ - countsPerSecond(); // good place to calculate clock frequency - U64 frame_time = getCPUClockCount64(); - if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff) - { - llinfos << "Slow frame, fast timers inaccurate" << llendl; - } - - if (!sPauseHistory) - { - NamedTimer::processTimes(); - sLastFrameIndex = sCurFrameIndex++; - } - - // get ready for next frame - NamedTimer::resetFrame(); - sLastFrameTime = frame_time; -} - -//static -void LLFastTimer::dumpCurTimes() -{ - // accumulate timings, etc. - NamedTimer::processTimes(); - - F64 clock_freq = (F64)countsPerSecond(); - F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); // walk over timers in depth order and output timings - for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + for(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimeBlock()); it != end_timer_tree(); ++it) { - NamedTimer* timerp = (*it); - F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq); + TimeBlock* timerp = (*it); + LLUnit<F64, LLUnits::Seconds> total_time = last_frame_recording.getSum(*timerp); + U32 num_calls = last_frame_recording.getSum(timerp->callCount()); + // Don't bother with really brief times, keep output concise - if (total_time_ms < 0.1) continue; + if (total_time < LLUnit<F32, LLUnits::Milliseconds>(0.1)) continue; std::ostringstream out_str; - for (S32 i = 0; i < timerp->getDepth(); i++) + TimeBlock* parent_timerp = timerp; + while(parent_timerp && parent_timerp != parent_timerp->getParent()) { out_str << "\t"; + parent_timerp = parent_timerp->getParent(); } - out_str << timerp->getName() << " " - << std::setprecision(3) << total_time_ms << " ms, " - << timerp->getHistoricalCalls(0) << " calls"; + << std::setprecision(3) << total_time.getAs<LLUnits::Milliseconds>() << " ms, " + << num_calls << " calls"; llinfos << out_str.str() << llendl; } } //static -void LLFastTimer::reset() -{ - NamedTimer::reset(); -} - - -//static -void LLFastTimer::writeLog(std::ostream& os) +void TimeBlock::writeLog(std::ostream& os) { while (!sLogQueue.empty()) { @@ -641,22 +416,62 @@ void LLFastTimer::writeLog(std::ostream& os) } } -//static -const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name) +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TimeBlockAccumulator +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TimeBlockAccumulator::TimeBlockAccumulator() +: mTotalTimeCounter(0), + mSelfTimeCounter(0), + mStartTotalTimeCounter(0), + mCalls(0), + mLastCaller(NULL), + mActiveCount(0), + mMoveUpTree(false), + mParent(NULL) +{} + +void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other, bool append ) { - return NamedTimerFactory::instance().getTimerByName(name); + // we can't merge two unrelated time block samples, as that will screw with the nested timings + // due to the call hierarchy of each thread + llassert(append); + mTotalTimeCounter += other.mTotalTimeCounter - other.mStartTotalTimeCounter; + mSelfTimeCounter += other.mSelfTimeCounter; + mCalls += other.mCalls; + mLastCaller = other.mLastCaller; + mActiveCount = other.mActiveCount; + mMoveUpTree = other.mMoveUpTree; + mParent = other.mParent; } -LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state) -: mFrameState(state) +void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other ) { - U32 start_time = getCPUClockCount32(); - mStartTime = start_time; - mFrameState->mActiveCount++; - LLFastTimer::sCurTimerData.mCurTimer = this; - LLFastTimer::sCurTimerData.mFrameState = mFrameState; - LLFastTimer::sCurTimerData.mChildTime = 0; - mLastTimerData = LLFastTimer::sCurTimerData; + mCalls = 0; + mSelfTimeCounter = 0; + + if (other) + { + mStartTotalTimeCounter = other->mTotalTimeCounter; + mTotalTimeCounter = mStartTotalTimeCounter; + + mLastCaller = other->mLastCaller; + mActiveCount = other->mActiveCount; + mMoveUpTree = other->mMoveUpTree; + mParent = other->mParent; + } + else +{ + mStartTotalTimeCounter = mTotalTimeCounter; + } +} + +LLUnit<F64, LLUnits::Seconds> BlockTimer::getElapsedTime() +{ + U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime; + + return (F64)total_time / (F64)TimeBlock::countsPerSecond(); } +} // namespace LLTrace diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 81c4b78775..642c99ccce 100755 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -28,216 +28,96 @@ #define LL_FASTTIMER_H #include "llinstancetracker.h" +#include "lltrace.h" #define FAST_TIMER_ON 1 -#define DEBUG_FAST_TIMER_THREADS 1 +#define LL_FASTTIMER_USE_RDTSC 1 class LLMutex; -#include <queue> -#include "llsd.h" - -#define LL_FASTTIMER_USE_RDTSC 1 - +namespace LLTrace +{ -LL_COMMON_API void assert_main_thread(); +struct BlockTimerStackRecord +{ + class BlockTimer* mActiveTimer; + class TimeBlock* mTimeBlock; + U64 mChildTime; +}; -class LL_COMMON_API LLFastTimer +class ThreadTimerStack +: public BlockTimerStackRecord, + public LLThreadLocalSingleton<ThreadTimerStack> { -public: - class NamedTimer; + friend class LLThreadLocalSingleton<ThreadTimerStack>; + ThreadTimerStack() + {} - struct LL_COMMON_API FrameState - { - FrameState(); - void setNamedTimer(NamedTimer* timerp) { mTimer = 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> +public: + ThreadTimerStack& operator=(const BlockTimerStackRecord& other) { - 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<NamedTimer*>::const_iterator child_const_iter; - child_const_iter beginChildren(); - child_const_iter endChildren(); - std::vector<NamedTimer*>& getChildren(); - - void setCollapsed(bool collapsed) { mCollapsed = collapsed; } - bool getCollapsed() const { return mCollapsed; } - - U32 getCountAverage() const { return mCountAverage; } - U32 getCallAverage() const { return mCallAverage; } - - U32 getHistoricalCount(S32 history_index = 0) const; - U32 getHistoricalCalls(S32 history_index = 0) const; - - static NamedTimer& getRootNamedTimer(); - - void setFrameState(FrameState* state) { mFrameState = state; state->setNamedTimer(this); } - FrameState& getFrameState() const; - - private: - friend class LLFastTimer; - friend class NamedTimerFactory; - - // - // methods - // - NamedTimer(const std::string& name); - // recursive call to gather total time from children - static void accumulateTimings(); - - // updates cumulative times and hierarchy, - // can be called multiple times in a frame, at any point - static void processTimes(); - - static void buildHierarchy(); - static void resetFrame(); - static void reset(); - - // - // members - // - FrameState* mFrameState; - - std::string mName; + BlockTimerStackRecord::operator=(other); + return *this; + } +}; - U32 mTotalTimeCounter; +class BlockTimer +{ +public: + friend class TimeBlock; + typedef BlockTimer self_t; + typedef class TimeBlock DeclareTimer; - U32 mCountAverage; - U32 mCallAverage; + BlockTimer(TimeBlock& timer); + ~BlockTimer(); - U32* mCountHistory; - U32* mCallHistory; + LLUnit<F64, LLUnits::Seconds> getElapsedTime(); - // 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 - }; +private: - // 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); + U64 mStartTime; + U64 mBlockStartTotalTimeCounter; + BlockTimerStackRecord mParentTimerData; +}; - NamedTimer& getNamedTimer() { return mTimer; } +// stores a "named" timer instance to be reused via multiple BlockTimer stack instances +class TimeBlock +: public TraceType<TimeBlockAccumulator>, + public LLInstanceTracker<TimeBlock> +{ +public: + TimeBlock(const char* name, TimeBlock* parent = &getRootTimeBlock()); - private: - FrameState mFrameState; - NamedTimer& mTimer; - }; + TimeBlockTreeNode& getTreeNode() const; + TimeBlock* getParent() const { return getTreeNode().getParent(); } + void setParent(TimeBlock* parent) { getTreeNode().setParent(parent); } -public: - LLFastTimer(LLFastTimer::FrameState* state); + typedef std::vector<TimeBlock*>::iterator child_iter; + typedef std::vector<TimeBlock*>::const_iterator child_const_iter; + child_iter beginChildren(); + child_iter endChildren(); + std::vector<TimeBlock*>& getChildren(); - LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer) - : mFrameState(&timer.mFrameState) + TraceType<TimeBlockAccumulator::CallCountFacet>& callCount() { -#if FAST_TIMER_ON - LLFastTimer::FrameState* frame_state = mFrameState; - mStartTime = getCPUClockCount32(); - - frame_state->mActiveCount++; - frame_state->mCalls++; - // keep current parent as long as it is active when we are - frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); - - LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData; - mLastTimerData = *cur_timer_data; - cur_timer_data->mCurTimer = this; - cur_timer_data->mFrameState = frame_state; - cur_timer_data->mChildTime = 0; -#endif -#if DEBUG_FAST_TIMER_THREADS -#if !LL_RELEASE - assert_main_thread(); -#endif -#endif + return static_cast<TraceType<TimeBlockAccumulator::CallCountFacet>&>(*(TraceType<TimeBlockAccumulator>*)this); } - LL_FORCE_INLINE ~LLFastTimer() + TraceType<TimeBlockAccumulator::SelfTimeFacet>& selfTime() { -#if FAST_TIMER_ON - LLFastTimer::FrameState* frame_state = mFrameState; - U32 total_time = getCPUClockCount32() - mStartTime; - - frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime; - frame_state->mActiveCount--; - - // store last caller to bootstrap tree creation - // do this in the destructor in case of recursion to get topmost caller - frame_state->mLastCaller = mLastTimerData.mFrameState; - - // we are only tracking self time, so subtract our total time delta from parents - mLastTimerData.mChildTime += total_time; - - LLFastTimer::sCurTimerData = mLastTimerData; -#endif + return static_cast<TraceType<TimeBlockAccumulator::SelfTimeFacet>&>(*(TraceType<TimeBlockAccumulator>*)this); } -public: - static LLMutex* sLogLock; - static std::queue<LLSD> sLogQueue; - static BOOL sLog; - static BOOL sMetricLog; - static std::string sLogName; - static bool sPauseHistory; - static bool sResetHistory; - - // call this once a frame to reset timers - static void nextFrame(); + static TimeBlock& getRootTimeBlock(); + static void pushLog(LLSD sd); + static void setLogLock(LLMutex* mutex); + static void writeLog(std::ostream& os); + static void updateTimes(); // dumps current cumulative frame stats to log // call nextFrame() to reset timers static void dumpCurTimes(); - // call this to reset timer hierarchy, averages, etc. - static void reset(); - - static U64 countsPerSecond(); - static S32 getLastFrameIndex() { return sLastFrameIndex; } - static S32 getCurFrameIndex() { return sCurFrameIndex; } - - static void writeLog(std::ostream& os); - static const NamedTimer* getTimerByName(const std::string& name); - - struct CurTimerData - { - LLFastTimer* mCurTimer; - FrameState* mFrameState; - U32 mChildTime; - }; - static CurTimerData sCurTimerData; - -private: - - ////////////////////////////////////////////////////////////////////////////// // // Important note: These implementations must be FAST! @@ -260,14 +140,14 @@ private: //#undef _interlockedbittestandset //#undef _interlockedbittestandreset - //inline U32 LLFastTimer::getCPUClockCount32() + //inline U32 TimeBlock::getCPUClockCount32() //{ // U64 time_stamp = __rdtsc(); // return (U32)(time_stamp >> 8); //} // //// return full timer value, *not* shifted by 8 bits - //inline U64 LLFastTimer::getCPUClockCount64() + //inline U64 TimeBlock::getCPUClockCount64() //{ // return __rdtsc(); //} @@ -307,7 +187,7 @@ private: } #else - //LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp + //U64 get_clock_count(); // in lltimer.cpp // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. static U32 getCPUClockCount32() { @@ -374,18 +254,74 @@ private: #endif - static U64 sClockResolution; + static U64 countsPerSecond(); + + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); + + static void bootstrapTimerTree(); + static void incrementalUpdateTimerTree(); - static S32 sCurFrameIndex; - static S32 sLastFrameIndex; - static U64 sLastFrameTime; + // call this once a frame to periodically log timers + static void logStats(); - U32 mStartTime; - LLFastTimer::FrameState* mFrameState; - LLFastTimer::CurTimerData mLastTimerData; + bool mCollapsed; // don't show children + // statics + static std::string sLogName; + static bool sMetricLog, + sLog; + static U64 sClockResolution; }; -typedef class LLFastTimer LLFastTimer; +LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer) +{ +#if FAST_TIMER_ON + BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists(); + TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator(); + accumulator->mActiveCount++; + mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter; + // keep current parent as long as it is active when we are + accumulator->mMoveUpTree |= (accumulator->mParent->getPrimaryAccumulator()->mActiveCount == 0); + + // store top of stack + mParentTimerData = *cur_timer_data; + // push new information + cur_timer_data->mActiveTimer = this; + cur_timer_data->mTimeBlock = &timer; + cur_timer_data->mChildTime = 0; + + mStartTime = TimeBlock::getCPUClockCount64(); +#endif +} + +LL_FORCE_INLINE BlockTimer::~BlockTimer() +{ +#if FAST_TIMER_ON + U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime; + BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists(); + TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator(); + + accumulator->mCalls++; + accumulator->mTotalTimeCounter += total_time - (accumulator->mTotalTimeCounter - mBlockStartTotalTimeCounter); + accumulator->mSelfTimeCounter += total_time - cur_timer_data->mChildTime; + accumulator->mActiveCount--; + + // store last caller to bootstrap tree creation + // do this in the destructor in case of recursion to get topmost caller + accumulator->mLastCaller = mParentTimerData.mTimeBlock; + + // we are only tracking self time, so subtract our total time delta from parents + mParentTimerData.mChildTime += total_time; + + //pop stack + *cur_timer_data = mParentTimerData; +#endif +} + +} + +typedef LLTrace::BlockTimer LLFastTimer; #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index c3a0f0bfe0..06bc931dea 100755 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -28,7 +28,7 @@ */ #if LL_WINDOWS -#include <windows.h> +#include "llwin32headerslean.h" #include <stdlib.h> // Windows errno #else #include <errno.h> @@ -438,7 +438,7 @@ llstdio_filebuf::int_type llstdio_filebuf::overflow(llstdio_filebuf::int_type __ _M_set_buffer(0); __ret = traits_type::not_eof(__c); } - } + } else if (_M_buf_size > 1) { // Overflow in 'uncommitted' mode: set _M_writing, set @@ -496,11 +496,11 @@ bool llstdio_filebuf::_convert_to_external(char_type* __ibuf, if (__r == codecvt_base::ok || __r == codecvt_base::partial) __blen = __bend - __buf; else if (__r == codecvt_base::noconv) - { + { // Same as the always_noconv case above. __buf = reinterpret_cast<char*>(__ibuf); __blen = __ilen; - } + } else __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external " "conversion error")); @@ -643,9 +643,9 @@ llstdio_filebuf::int_type llstdio_filebuf::underflow() _M_ext_end, _M_ext_next, this->eback(), this->eback() + __buflen, __iend); -} + } if (__r == codecvt_base::noconv) -{ + { size_t __avail = _M_ext_end - _M_ext_buf; __ilen = std::min(__avail, __buflen); traits_type::copy(this->eback(), @@ -806,15 +806,15 @@ std::streamsize llstdio_filebuf::xsputn(char_type* __s, std::streamsize __n) __ret = fwrite(__buf, 1, __buffill, _M_file.file()); } if (__ret == __buffill) - { + { __ret += fwrite(reinterpret_cast<const char*>(__s), 1, __n, _M_file.file()); - } + } if (__ret == __buffill + __n) { _M_set_buffer(0); _M_writing = true; -} + } if (__ret > __buffill) __ret -= __buffill; else @@ -848,7 +848,7 @@ llifstream::llifstream() : _M_filebuf(), #endif // explicit -llifstream::llifstream(const std::string& _Filename, +llifstream::llifstream(const std::string& _Filename, ios_base::openmode _Mode) : _M_filebuf(), #if LL_WINDOWS std::istream(&_M_filebuf) @@ -877,7 +877,7 @@ llifstream::llifstream(const char* _Filename, if (_M_filebuf.open(wideName.c_str(), _Mode | ios_base::in) == 0) { _Myios::setstate(ios_base::failbit); -} + } } #else std::istream() @@ -951,8 +951,8 @@ void llifstream::close() #else this->setstate(ios_base::failbit); #endif - } } +} /************** output file stream ********************************/ @@ -1042,7 +1042,7 @@ void llofstream::open(const char* _Filename, ios_base::openmode _Mode) #if LL_WINDOWS llutf16string wideName = utf8str_to_utf16str( _Filename ); if (_M_filebuf.open( wideName.c_str(), _Mode | ios_base::out) == 0) -{ + { _Myios::setstate(ios_base::failbit); } else diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp index cd7c0c7c09..f019bd0c64 100755 --- a/indra/llcommon/llfindlocale.cpp +++ b/indra/llcommon/llfindlocale.cpp @@ -33,7 +33,7 @@ #include <ctype.h> #ifdef WIN32 -#include <windows.h> +#include "llwin32headers.h" #include <winnt.h> #endif diff --git a/indra/llcommon/llindexedqueue.h b/indra/llcommon/llindexedqueue.h deleted file mode 100755 index aa2675d87d..0000000000 --- a/indra/llcommon/llindexedqueue.h +++ /dev/null @@ -1,155 +0,0 @@ -/** - * @file llindexedqueue.h - * @brief An indexed FIFO queue, where only one element with each key - * can be in the queue. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLINDEXEDQUEUE_H -#define LL_LLINDEXEDQUEUE_H - -// An indexed FIFO queue, where only one element with each key can be in the queue. -// This is ONLY used in the interest list, you'll probably want to review this code -// carefully if you want to use it elsewhere - Doug - -template <typename Type> -class LLIndexedQueue -{ -protected: - typedef std::deque<Type> type_deque; - type_deque mQueue; - std::set<Type> mKeySet; - -public: - LLIndexedQueue() {} - - // move_if_there is an O(n) operation - bool push_back(const Type &value, bool move_if_there = false) - { - if (mKeySet.find(value) != mKeySet.end()) - { - // Already on the queue - if (move_if_there) - { - // Remove the existing entry. - typename type_deque::iterator it; - for (it = mQueue.begin(); it != mQueue.end(); ++it) - { - if (*it == value) - { - break; - } - } - - // This HAS to succeed, otherwise there's a serious bug in the keyset implementation - // (although this isn't thread safe, at all) - - mQueue.erase(it); - } - else - { - // We're not moving it, leave it alone - return false; - } - } - else - { - // Doesn't exist, add it to the key set - mKeySet.insert(value); - } - - mQueue.push_back(value); - - // We succeeded in adding the new element. - return true; - } - - bool push_front(const Type &value, bool move_if_there = false) - { - if (mKeySet.find(value) != mKeySet.end()) - { - // Already on the queue - if (move_if_there) - { - // Remove the existing entry. - typename type_deque::iterator it; - for (it = mQueue.begin(); it != mQueue.end(); ++it) - { - if (*it == value) - { - break; - } - } - - // This HAS to succeed, otherwise there's a serious bug in the keyset implementation - // (although this isn't thread safe, at all) - - mQueue.erase(it); - } - else - { - // We're not moving it, leave it alone - return false; - } - } - else - { - // Doesn't exist, add it to the key set - mKeySet.insert(value); - } - - mQueue.push_front(value); - return true; - } - - void pop() - { - Type value = mQueue.front(); - mKeySet.erase(value); - mQueue.pop_front(); - } - - Type &front() - { - return mQueue.front(); - } - - S32 size() const - { - return mQueue.size(); - } - - bool empty() const - { - return mQueue.empty(); - } - - void clear() - { - // Clear out all elements on the queue - mQueue.clear(); - mKeySet.clear(); - } -}; - -#endif // LL_LLINDEXEDQUEUE_H diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp index 89c831d296..dbd4eba7a0 100755 --- a/indra/llcommon/llinitparam.cpp +++ b/indra/llcommon/llinitparam.cpp @@ -28,10 +28,17 @@ #include "linden_common.h" #include "llinitparam.h" +#include "llformat.h" namespace LLInitParam { + + predicate_rule_t default_parse_rules() + { + return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY); + } + // // Param // @@ -196,6 +203,9 @@ namespace LLInitParam bool BaseBlock::validateBlock(bool emit_errors) const { + // only validate block when it hasn't already passed validation with current data + if (!mValidated) + { const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it) { @@ -209,11 +219,18 @@ namespace LLInitParam return false; } } - return true; + mValidated = true; + } + return mValidated; } - void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const + bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const { + bool serialized = false; + if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided()))) + { + return false; + } // named param is one like LLView::Params::follows // unnamed param is like LLView::Params::rect - implicit const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); @@ -225,10 +242,10 @@ namespace LLInitParam param_handle_t param_handle = (*it)->mParamHandle; const Param* param = getParamFromHandle(param_handle); ParamDescriptor::serialize_func_t serialize_func = (*it)->mSerializeFunc; - if (serialize_func) + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) { const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialize_func(*param, parser, name_stack, diff_param); + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); } } @@ -239,7 +256,7 @@ namespace LLInitParam param_handle_t param_handle = it->second->mParamHandle; const Param* param = getParamFromHandle(param_handle); ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc; - if (serialize_func && param->anyProvided()) + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) { // Ensure this param has not already been serialized // Prevents <rect> from being serialized as its own tag. @@ -264,10 +281,17 @@ namespace LLInitParam name_stack.push_back(std::make_pair(it->first, !duplicate)); const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialize_func(*param, parser, name_stack, diff_param); + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); name_stack.pop_back(); } } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + // was anything serialized in this block? + return serialized; } bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index ae836645b9..879ea4fe2a 100755 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -29,14 +29,15 @@ #define LL_LLPARAM_H #include <vector> +#include <list> #include <boost/function.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/is_enum.hpp> #include <boost/unordered_map.hpp> -#include <boost/shared_ptr.hpp> #include "llerror.h" #include "llstl.h" +#include "llpredicate.h" namespace LLTypeTags { @@ -195,6 +196,8 @@ namespace LLInitParam return mValue; } + bool isValid() const { return true; } + protected: T mValue; }; @@ -209,13 +212,11 @@ namespace LLInitParam typedef T value_t; ParamValue() - : T(), - mValidated(false) + : T() {} ParamValue(const default_value_t& other) - : T(other), - mValidated(false) + : T(other) {} void setValue(const value_t& val) @@ -232,9 +233,6 @@ namespace LLInitParam { return *this; } - - protected: - mutable bool mValidated; // lazy validation flag }; @@ -497,25 +495,25 @@ namespace LLInitParam virtual ~Parser(); template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0) - { + { parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); if (found_it != mParserReadFuncs->end()) - { + { return found_it->second(*this, (void*)¶m); - } - - return false; } + return false; + } + template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0) - { + { parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); if (found_it != mParserReadFuncs->end()) - { + { return found_it->second(*this, (void*)¶m); - } + } else - { + { found_it = mParserReadFuncs->find(&typeid(S32)); if (found_it != mParserReadFuncs->end()) { @@ -579,6 +577,19 @@ namespace LLInitParam class Param; + enum ESerializePredicates + { + PROVIDED, + REQUIRED, + VALID, + HAS_DEFAULT_VALUE, + EMPTY + }; + + typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t; + + predicate_rule_t default_parse_rules(); + // various callbacks and constraints associated with an individual param struct LL_COMMON_API ParamDescriptor { @@ -589,7 +600,7 @@ namespace LLInitParam typedef bool(*merge_func_t)(Param&, const Param&, bool); typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); - typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param); + typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param); typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); typedef bool(*validation_func_t)(const Param*); @@ -617,7 +628,7 @@ namespace LLInitParam UserData* mUserData; }; - typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr; + typedef ParamDescriptor* ParamDescriptorPtr; // each derived Block class keeps a static data structure maintaining offsets to various params class LL_COMMON_API BlockDescriptor @@ -829,12 +840,28 @@ namespace LLInitParam LOG_CLASS(BaseBlock); friend class Param; + BaseBlock() + : mValidated(false), + mParamProvided(false) + {} + virtual ~BaseBlock() {} bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); param_handle_t getHandleFromParam(const Param* param) const; bool validateBlock(bool emit_errors = true) const; + bool isProvided() const + { + return mParamProvided; + } + + bool isValid() const + { + return validateBlock(false); + } + + Param* getParamFromHandle(const param_handle_t param_handle) { if (param_handle == 0) return NULL; @@ -852,10 +879,19 @@ namespace LLInitParam void addSynonym(Param& param, const std::string& synonym); // Blocks can override this to do custom tracking of changes - virtual void paramChanged(const Param& changed_param, bool user_provided) {} + virtual void paramChanged(const Param& changed_param, bool user_provided) + { + if (user_provided) + { + // a child param has been explicitly changed + // so *some* aspect of this block is now provided + mValidated = false; + mParamProvided = true; + } + } bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } @@ -893,6 +929,9 @@ namespace LLInitParam return mergeBlock(block_data, source, overwrite); } + mutable bool mValidated; // lazy validation flag + bool mParamProvided; + private: const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; }; @@ -986,6 +1025,8 @@ namespace LLInitParam bool isProvided() const { return Param::anyProvided(); } + bool isValid() const { return true; } + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { self_t& typed_param = static_cast<self_t&>(param); @@ -1014,10 +1055,23 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + const self_t* diff_typed_param = static_cast<const self_t*>(diff_param); + + LLPredicate::Value<ESerializePredicates> predicate; + if (diff_typed_param && ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) + { + predicate.set(HAS_DEFAULT_VALUE); + } + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, false); + + if (!predicate_rule.check(predicate)) return false; if (!name_stack.empty()) { @@ -1030,25 +1084,27 @@ namespace LLInitParam if (!key.empty()) { - if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key)) + if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key)) { - parser.writeValue(key, name_stack); + serialized = parser.writeValue(key, name_stack); } } // then try to serialize value directly - else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), static_cast<const self_t*>(diff_param)->getValue())) + else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) { - if (!parser.writeValue(typed_param.getValue(), name_stack)) + serialized = parser.writeValue(typed_param.getValue(), name_stack); + if (!serialized) { std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); if (calculated_key.size() - && (!diff_param + && (!diff_typed_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))) { - parser.writeValue(calculated_key, name_stack); + serialized = parser.writeValue(calculated_key, name_stack); } } } + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) @@ -1113,19 +1169,19 @@ namespace LLInitParam }; // parameter that is a block - template <typename T, typename NAME_VALUE_LOOKUP> - class TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> + template <typename BLOCK_T, typename NAME_VALUE_LOOKUP> + class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> : public Param, public NAME_VALUE_LOOKUP::type_value_t { protected: - typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; - typedef typename param_value_t::default_value_t default_value_t; - typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + typedef ParamValue<typename LLTypeTags::Sorted<BLOCK_T>::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; public: using named_value_t::operator(); - typedef typename param_value_t::value_t value_t; + typedef typename param_value_t::value_t value_t; TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) : Param(block_descriptor.mCurrentBlockPtr), @@ -1148,11 +1204,11 @@ namespace LLInitParam if(named_value_t::valueNamesExist() && parser.readValue(name) && named_value_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } } if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) @@ -1166,10 +1222,16 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + + if (!predicate_rule.check(predicate)) return false; if (!name_stack.empty()) { @@ -1182,12 +1244,15 @@ namespace LLInitParam if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key)) { parser.writeValue(key, name_stack); + return true; } } else { - typed_param.serializeBlock(parser, name_stack, static_cast<const self_t*>(diff_param)); + return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param)); } + + return false; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) @@ -1209,13 +1274,12 @@ namespace LLInitParam // *and* the block as a whole validates bool isProvided() const { - // only validate block when it hasn't already passed validation with current data - if (Param::anyProvided() && !param_value_t::mValidated) - { - // a sub-block is "provided" when it has been filled in enough to be valid - param_value_t::mValidated = param_value_t::validateBlock(false); - } - return Param::anyProvided() && param_value_t::mValidated; + return Param::anyProvided() && isValid(); + } + + bool isValid() const + { + return param_value_t::isValid(); } // assign block contents to this param-that-is-a-block @@ -1223,9 +1287,6 @@ namespace LLInitParam { setValue(val); named_value_t::clearValueName(); - // force revalidation of block - // next call to isProvided() will update provision status based on validity - param_value_t::mValidated = false; setProvided(flag_as_provided); } @@ -1242,9 +1303,6 @@ namespace LLInitParam if (user_provided) { - // a child param has been explicitly changed - // so *some* aspect of this block is now provided - param_value_t::mValidated = false; setProvided(); named_value_t::clearValueName(); } @@ -1296,13 +1354,13 @@ namespace LLInitParam }; // list of non-block parameters - template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP> - class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK> + template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP> + class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> : public Param { protected: - typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t; - typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t; + typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t; + typedef ParamValue<typename LLTypeTags::Sorted<MULTI_VALUE_T>::value_t> param_value_t; typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; typedef container_t default_value_t; typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; @@ -1311,7 +1369,9 @@ namespace LLInitParam typedef typename param_value_t::value_t value_t; TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) { std::copy(value.begin(), value.end(), std::back_inserter(mValues)); @@ -1322,7 +1382,13 @@ namespace LLInitParam } } - bool isProvided() const { return Param::anyProvided(); } + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { @@ -1337,7 +1403,7 @@ namespace LLInitParam } // no further names in stack, attempt to parse value now - if (name_stack_range.first == name_stack_range.second) + if (new_name_stack_range.first == new_name_stack_range.second) { std::string name; @@ -1359,10 +1425,19 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; @@ -1378,7 +1453,11 @@ namespace LLInitParam if (!value_written) { std::string calculated_key = it->calcValueName(it->getValue()); - if (!parser.writeValue(calculated_key, name_stack)) + if (parser.writeValue(calculated_key, name_stack)) + { + serialized = true; + } + else { break; } @@ -1386,19 +1465,23 @@ namespace LLInitParam } else { - if(!parser.writeValue(key, name_stack)) + if(parser.writeValue(key, name_stack)) + { + serialized = true; + } + else { break; } } - - name_stack.pop_back(); } + + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { - parser.inspectValue<VALUE_TYPE>(name_stack, min_count, max_count, NULL); + parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL); if (named_value_t::getPossibleValues()) { parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); @@ -1453,7 +1536,7 @@ namespace LLInitParam bool empty() const { return mValues.empty(); } size_t size() const { return mValues.size(); } - U32 numValidElements() const + size_t numValidElements() const { return mValues.size(); } @@ -1483,6 +1566,8 @@ namespace LLInitParam } container_t mValues; + size_t mMinCount, + mMaxCount; private: void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) @@ -1500,13 +1585,13 @@ namespace LLInitParam }; // list of block parameters - template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP> - class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> + template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP> + class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> : public Param { protected: - typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t; - typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t; + typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t; + typedef ParamValue<typename LLTypeTags::Sorted<MULTI_BLOCK_T>::value_t> param_value_t; typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; typedef container_t default_value_t; @@ -1516,7 +1601,9 @@ namespace LLInitParam typedef typename param_value_t::value_t value_t; TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) { std::copy(value.begin(), value.end(), back_inserter(mValues)); @@ -1526,7 +1613,14 @@ namespace LLInitParam } } - bool isProvided() const { return Param::anyProvided(); } + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { @@ -1549,7 +1643,7 @@ namespace LLInitParam } param_value_t& value = typed_param.mValues.back(); - if (name_stack_range.first == name_stack_range.second) + if (new_name_stack_range.first == new_name_stack_range.second) { // try to parse a known named value std::string name; @@ -1559,6 +1653,10 @@ namespace LLInitParam { typed_param.mValues.back().setValueName(name); typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } return true; } } @@ -1583,10 +1681,18 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; @@ -1597,17 +1703,24 @@ namespace LLInitParam std::string key = it->getValueName(); if (!key.empty()) { - parser.writeValue(key, name_stack); + serialized |= parser.writeValue(key, name_stack); } // Not parsed via named values, write out value directly - // NOTE: currently we don't worry about removing default values in Multiple + // NOTE: currently we don't do diffing of Multiples else { - it->serializeBlock(parser, name_stack, NULL); + serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL); } name_stack.pop_back(); } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) @@ -1670,14 +1783,14 @@ namespace LLInitParam bool empty() const { return mValues.empty(); } size_t size() const { return mValues.size(); } - U32 numValidElements() const + size_t numValidElements() const { - U32 count = 0; + size_t count = 0; for (const_iterator it = mValues.begin(), end_it = mValues.end(); it != end_it; ++it) { - if(it->validateBlock(false)) count++; + if(it->isValid()) count++; } return count; } @@ -1709,6 +1822,8 @@ namespace LLInitParam } container_t mValues; + size_t mMinCount, + mMaxCount; private: void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) @@ -2015,7 +2130,7 @@ namespace LLInitParam static bool validate(const Param* paramp) { - U32 num_valid = ((super_t*)paramp)->numValidElements(); + size_t num_valid = ((super_t*)paramp)->numValidElements(); return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; } }; @@ -2158,13 +2273,11 @@ namespace LLInitParam typedef T default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() {} ParamValue(const default_value_t& value) - : mValue(value), - mValidated(false) + : mValue(value) {} void setValue(const value_t& val) @@ -2191,18 +2304,18 @@ namespace LLInitParam return mValue.deserializeBlock(p, name_stack_range, new_name); } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { const BaseBlock* base_block = diff_block ? &(diff_block->mValue) : NULL; - mValue.serializeBlock(p, name_stack, base_block); + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); } bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { + { return mValue.inspectBlock(p, name_stack, min_count, max_count); - } + } bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) { @@ -2212,9 +2325,7 @@ namespace LLInitParam // clear away what is there and take the new stuff as a whole resetToDefault(); return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - - + } return mValue.mergeBlock(block_data, source.getValue(), overwrite); } @@ -2223,14 +2334,17 @@ namespace LLInitParam return mValue.validateBlock(emit_errors); } + bool isValid() const + { + return validateBlock(false); + } + static BlockDescriptor& getBlockDescriptor() { return value_t::getBlockDescriptor(); } - mutable bool mValidated; // lazy validation flag - private: void resetToDefault() { @@ -2251,15 +2365,13 @@ namespace LLInitParam typedef T default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() { mCurParam = getBlockDescriptor().mAllParams.begin(); } ParamValue(const default_value_t& value) - : mValue(value), - mValidated(false) + : mValue(value) { mCurParam = getBlockDescriptor().mAllParams.begin(); } @@ -2284,7 +2396,7 @@ namespace LLInitParam if (new_name) { mCurParam = getBlockDescriptor().mAllParams.begin(); - } + } if (name_stack_range.first == name_stack_range.second && mCurParam != getBlockDescriptor().mAllParams.end()) { @@ -2296,7 +2408,7 @@ namespace LLInitParam if (deserialize_func && paramp && deserialize_func(*paramp, p, name_stack_range, new_name)) - { + { ++mCurParam; return true; } @@ -2304,19 +2416,19 @@ namespace LLInitParam { return false; } - } + } else { return mValue.deserializeBlock(p, name_stack_range, new_name); } } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { const BaseBlock* base_block = diff_block ? &(diff_block->mValue) : NULL; - mValue.serializeBlock(p, name_stack, base_block); + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); } bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const @@ -2334,13 +2446,16 @@ namespace LLInitParam return mValue.validateBlock(emit_errors); } + bool isValid() const + { + return validateBlock(false); + } + static BlockDescriptor& getBlockDescriptor() { return value_t::getBlockDescriptor(); } - mutable bool mValidated; // lazy validation flag - private: BlockDescriptor::all_params_list_t::iterator mCurParam; @@ -2358,16 +2473,14 @@ namespace LLInitParam typedef T default_value_t; ParamValue() - : T(), - mValidated(false) + : T() {} ParamValue(const default_value_t& value) - : T(value.getValue()), - mValidated(false) + : T(value.getValue()) {} - mutable bool mValidated; // lazy validation flag + bool isValid() const { return true; } }; template<typename T, typename BLOCK_T> @@ -2380,18 +2493,15 @@ namespace LLInitParam typedef LazyValue<T> default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() {} ParamValue(const default_value_t& other) - : mValue(other), - mValidated(false) + : mValue(other) {} ParamValue(const T& value) - : mValue(value), - mValidated(false) + : mValue(value) {} void setValue(const value_t& val) @@ -2414,14 +2524,14 @@ namespace LLInitParam return mValue.get().deserializeBlock(p, name_stack_range, new_name); } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { - if (mValue.empty()) return; + if (mValue.empty()) return false; const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) ? &(diff_block->mValue.get().getValue()) : NULL; - mValue.get().serializeBlock(p, name_stack, base_block); + return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_block); } bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const @@ -2433,26 +2543,29 @@ namespace LLInitParam { return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); } - + bool validateBlock(bool emit_errors = true) const { return mValue.empty() || mValue.get().validateBlock(emit_errors); } + bool isValid() const + { + return validateBlock(false); + } + static BlockDescriptor& getBlockDescriptor() { return value_t::getBlockDescriptor(); } - mutable bool mValidated; // lazy validation flag - private: LazyValue<T> mValue; }; template<typename T, typename BLOCK_T> class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> - { + { typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t; public: @@ -2460,18 +2573,15 @@ namespace LLInitParam typedef LazyValue<T> default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() {} ParamValue(const default_value_t& other) - : mValue(other), - mValidated(false) + : mValue(other) {} ParamValue(const T& value) - : mValue(value), - mValidated(false) + : mValue(value) {} void setValue(const value_t& val) @@ -2489,7 +2599,10 @@ namespace LLInitParam return mValue.get().getValue(); } - mutable bool mValidated; // lazy validation flag + bool isValid() const + { + return true; + } private: LazyValue<T> mValue; @@ -2504,12 +2617,10 @@ namespace LLInitParam typedef LLSD default_value_t; ParamValue() - : mValidated(false) {} ParamValue(const default_value_t& other) - : mValue(other), - mValidated(false) + : mValue(other) {} void setValue(const value_t& val) { mValue = val; } @@ -2519,16 +2630,13 @@ namespace LLInitParam // block param interface LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const { //TODO: implement LLSD params as schema type Any return true; } - protected: - mutable bool mValidated; // lazy validation flag - private: static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); @@ -2547,18 +2655,17 @@ namespace LLInitParam BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative } EValueAge; - typedef ParamValue<T> derived_t; - typedef CustomParamValue<T> self_t; - typedef Block<derived_t> block_t; + typedef TypeValues<T> derived_t; + typedef CustomParamValue<T> self_t; + typedef Block<ParamValue<T> > block_t; typedef T default_value_t; - typedef T value_t; + typedef T value_t; typedef void baseblock_base_class_t; CustomParamValue(const default_value_t& value = T()) : mValue(value), - mValueAge(VALUE_AUTHORITATIVE), - mValidated(false) + mValueAge(VALUE_AUTHORITATIVE) {} bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) @@ -2580,16 +2687,30 @@ namespace LLInitParam return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); } - void serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const + bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const { const derived_t& typed_param = static_cast<const derived_t&>(*this); const derived_t* diff_param = static_cast<const derived_t*>(diff_block); + //std::string key = typed_param.getValueName(); + + //// first try to write out name of name/value pair + //if (!key.empty()) + //{ + // if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key)) + // { + // return parser.writeValue(key, name_stack); + // } + //} // then try to serialize value directly if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue())) { - if (!parser.writeValue(typed_param.getValue(), name_stack)) + if (parser.writeValue(typed_param.getValue(), name_stack)) + { + return true; + } + else { //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), // since these tend to be viewed as the constructor arguments for the value T. It seems @@ -2606,14 +2727,15 @@ namespace LLInitParam // and serialize those params derived_t copy(typed_param); copy.updateBlockFromValue(true); - copy.block_t::serializeBlock(parser, name_stack, NULL); + return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); } else { - block_t::serializeBlock(parser, name_stack, NULL); + return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); } } } + return false; } bool validateBlock(bool emit_errors = true) const @@ -2705,8 +2827,6 @@ namespace LLInitParam return block_t::mergeBlock(block_data, source, overwrite); } - mutable bool mValidated; // lazy validation flag - private: mutable T mValue; mutable EValueAge mValueAge; diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index 5dc3ea5d7b..7ff8324fe3 100755 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -27,23 +27,25 @@ #include "linden_common.h" // associated header #include "llinstancetracker.h" +#include "llapr.h" + // STL headers // std headers // external library headers // other Linden headers -//static -void * & LLInstanceTrackerBase::getInstances(std::type_info const & info) +void LLInstanceTrackerBase::StaticBase::incrementDepth() +{ + apr_atomic_inc32(&sIterationNestDepth); +} + +void LLInstanceTrackerBase::StaticBase::decrementDepth() { - typedef std::map<std::string, void *> InstancesMap; - static InstancesMap instances; + apr_atomic_dec32(&sIterationNestDepth); +} - // std::map::insert() is just what we want here. You attempt to insert a - // (key, value) pair. If the specified key doesn't yet exist, it inserts - // the pair and returns a std::pair of (iterator, true). If the specified - // key DOES exist, insert() simply returns (iterator, false). One lookup - // handles both cases. - return instances.insert(InstancesMap::value_type(info.name(), - InstancesMap::mapped_type())) - .first->second; +U32 LLInstanceTrackerBase::StaticBase::getDepth() +{ + apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth); + return data; } diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 1eab270e3c..c8e1d9cd84 100755 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -46,22 +46,6 @@ class LL_COMMON_API LLInstanceTrackerBase { protected: - /// Get a process-unique void* pointer slot for the specified type_info - static void * & getInstances(std::type_info const & info); - - /// Find or create a STATICDATA instance for the specified TRACKED class. - /// STATICDATA must be default-constructible. - template<typename STATICDATA, class TRACKED> - static STATICDATA& getStatic() - { - void *& instances = getInstances(typeid(TRACKED)); - if (! instances) - { - instances = new STATICDATA; - } - return *static_cast<STATICDATA*>(instances); - } - /// It's not essential to derive your STATICDATA (for use with /// getStatic()) from StaticBase; it's just that both known /// implementations do. @@ -70,15 +54,21 @@ protected: StaticBase(): sIterationNestDepth(0) {} - S32 sIterationNestDepth; + + void incrementDepth(); + void decrementDepth(); + U32 getDepth(); + private: + U32 sIterationNestDepth; }; }; /// This mix-in class adds support for tracking all instances of the specified class parameter T /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup /// If KEY is not provided, then instances are stored in a simple set -/// @NOTE: see explicit specialization below for default KEY==T* case -template<typename T, typename KEY = T*> +/// @NOTE: see explicit specialization below for default KEY==void case +/// @NOTE: this class is not thread-safe unless used as read-only +template<typename T, typename KEY = void> class LLInstanceTracker : public LLInstanceTrackerBase { typedef LLInstanceTracker<T, KEY> MyT; @@ -87,7 +77,7 @@ class LLInstanceTracker : public LLInstanceTrackerBase { InstanceMap sMap; }; - static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } + static StaticData& getStatic() { static StaticData sData; return sData;} static InstanceMap& getMap_() { return getStatic().sMap; } public: @@ -99,12 +89,12 @@ public: instance_iter(const typename InstanceMap::iterator& it) : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~instance_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } @@ -131,20 +121,20 @@ public: typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t; key_iter(typename InstanceMap::iterator it) - : mIterator(it) + : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } key_iter(const key_iter& other) - : mIterator(other.mIterator) + : mIterator(other.mIterator) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~key_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } @@ -182,7 +172,10 @@ public: return instance_iter(getMap_().end()); } - static S32 instanceCount() { return getMap_().size(); } + static S32 instanceCount() + { + return getMap_().size(); + } static key_iter beginKeys() { @@ -203,7 +196,7 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().sIterationNestDepth == 0); + llassert_always(getStatic().getDepth() == 0); remove_(); } virtual void setKey(KEY key) { remove_(); add_(key); } @@ -227,18 +220,18 @@ private: KEY mInstanceKey; }; -/// explicit specialization for default case where KEY is T* +/// explicit specialization for default case where KEY is void /// use a simple std::set<T*> template<typename T> -class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase +class LLInstanceTracker<T, void> : public LLInstanceTrackerBase { - typedef LLInstanceTracker<T, T*> MyT; + typedef LLInstanceTracker<T, void> MyT; typedef typename std::set<T*> InstanceSet; struct StaticData: public StaticBase { InstanceSet sSet; }; - static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); } + static StaticData& getStatic() { static StaticData sData; return sData; } static InstanceSet& getSet_() { return getStatic().sSet; } public: @@ -265,18 +258,18 @@ public: instance_iter(const typename InstanceSet::iterator& it) : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } instance_iter(const instance_iter& other) : mIterator(other.mIterator) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~instance_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } private: @@ -309,7 +302,7 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().sIterationNestDepth == 0); + llassert_always(getStatic().getDepth() == 0); getSet_().erase(static_cast<T*>(this)); } diff --git a/indra/llcommon/lllazy.h b/indra/llcommon/lllazy.h deleted file mode 100755 index 5f3bbce79e..0000000000 --- a/indra/llcommon/lllazy.h +++ /dev/null @@ -1,399 +0,0 @@ -/** - * @file lllazy.h - * @author Nat Goodspeed - * @date 2009-01-22 - * @brief Lazy instantiation of specified type. Useful in conjunction with - * Michael Feathers's "Extract and Override Getter" ("Working - * Effectively with Legacy Code", p. 352). - * - * Quoting his synopsis of steps on p.355: - * - * 1. Identify the object you need a getter for. - * 2. Extract all of the logic needed to create the object into a getter. - * 3. Replace all uses of the object with calls to the getter, and initialize - * the reference that holds the object to null in all constructors. - * 4. Add the first-time logic to the getter so that the object is constructed - * and assigned to the reference whenever the reference is null. - * 5. Subclass the class and override the getter to provide an alternative - * object for testing. - * - * It's the second half of bullet 3 (3b, as it were) that bothers me. I find - * it all too easy to imagine adding pointer initializers to all but one - * constructor... the one not exercised by my tests. That suggested using - * (e.g.) boost::scoped_ptr<MyObject> so you don't have to worry about - * destroying it either. - * - * However, introducing additional machinery allows us to encapsulate bullet 4 - * as well. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLLAZY_H) -#define LL_LLLAZY_H - -#include <boost/function.hpp> -#include <boost/scoped_ptr.hpp> -#include <boost/lambda/construct.hpp> -#include <stdexcept> - -/// LLLazyCommon simply factors out of LLLazy<T> things that don't depend on -/// its template parameter. -class LLLazyCommon -{ -public: - /** - * This exception is thrown if you try to replace an LLLazy<T>'s factory - * (or T* instance) after it already has an instance in hand. Since T - * might well be stateful, we can't know the effect of silently discarding - * and replacing an existing instance, so we disallow it. This facility is - * intended for testing, and in a test scenario we can definitely control - * that. - */ - struct InstanceChange: public std::runtime_error - { - InstanceChange(const std::string& what): std::runtime_error(what) {} - }; - -protected: - /** - * InstanceChange might be appropriate in a couple of different LLLazy<T> - * methods. Factor out the common logic. - */ - template <typename PTR> - static void ensureNoInstance(const PTR& ptr) - { - if (ptr) - { - // Too late: we've already instantiated the lazy object. We don't - // know whether it's stateful or not, so it's not safe to discard - // the existing instance in favor of a replacement. - throw InstanceChange("Too late to replace LLLazy instance"); - } - } -}; - -/** - * LLLazy<T> is useful when you have an outer class Outer that you're trying - * to bring under unit test, that contains a data member difficult to - * instantiate in a test harness. Typically the data member's class Inner has - * many thorny dependencies. Feathers generally advocates "Extract and - * Override Factory Method" (p. 350). But in C++, you can't call a derived - * class override of a virtual method from the derived class constructor, - * which limits applicability of "Extract and Override Factory Method." For - * such cases Feathers presents "Extract and Override Getter" (p. 352). - * - * So we'll assume that your class Outer contains a member like this: - * @code - * Inner mInner; - * @endcode - * - * LLLazy<Inner> can be used to replace this member. You can directly declare: - * @code - * LLLazy<Inner> mInner; - * @endcode - * and change references to mInner accordingly. - * - * (Alternatively, you can add a base class of the form - * <tt>LLLazyBase<Inner></tt>. This is discussed further in the LLLazyBase<T> - * documentation.) - * - * LLLazy<T> binds a <tt>boost::scoped_ptr<T></tt> and a factory functor - * returning T*. You can either bind that functor explicitly or let it default - * to the expression <tt>new T()</tt>. - * - * As long as LLLazy<T> remains unreferenced, its T remains uninstantiated. - * The first time you use get(), <tt>operator*()</tt> or <tt>operator->()</tt> - * it will instantiate its T and thereafter behave like a pointer to it. - * - * Thus, any existing reference to <tt>mInner.member</tt> should be replaced - * with <tt>mInner->member</tt>. Any simple reference to @c mInner should be - * replaced by <tt>*mInner</tt>. - * - * (If the original declaration was a pointer initialized in Outer's - * constructor, e.g. <tt>Inner* mInner</tt>, so much the better. In that case - * you should be able to drop in <tt>LLLazy<Inner></tt> without much change.) - * - * The support for "Extract and Override Getter" lies in the fact that you can - * replace the factory functor -- or provide an explicit T*. Presumably this - * is most useful from a test subclass -- which suggests that your @c mInner - * member should be @c protected. - * - * Note that <tt>boost::lambda::new_ptr<T>()</tt> makes a dandy factory - * functor, for either the set() method or LLLazy<T>'s constructor. If your T - * requires constructor arguments, use an expression more like - * <tt>boost::lambda::bind(boost::lambda::new_ptr<T>(), arg1, arg2, ...)</tt>. - * - * Of course the point of replacing the functor is to substitute a class that, - * though referenced as Inner*, is not an Inner; presumably this is a testing - * subclass of Inner (e.g. TestInner). Thus your test subclass TestOuter for - * the containing class Outer will contain something like this: - * @code - * class TestOuter: public Outer - * { - * public: - * TestOuter() - * { - * // mInner must be 'protected' rather than 'private' - * mInner.set(boost::lambda::new_ptr<TestInner>()); - * } - * ... - * }; - * @endcode - */ -template <typename T> -class LLLazy: public LLLazyCommon -{ -public: - /// Any nullary functor returning T* will work as a Factory - typedef boost::function<T* ()> Factory; - - /// The default LLLazy constructor uses <tt>new T()</tt> as its Factory - LLLazy(): - mFactory(boost::lambda::new_ptr<T>()) - {} - - /// Bind an explicit Factory functor - LLLazy(const Factory& factory): - mFactory(factory) - {} - - /// Reference T, instantiating it if this is the first access - const T& get() const - { - if (! mInstance) - { - // use the bound Factory functor - mInstance.reset(mFactory()); - } - return *mInstance; - } - - /// non-const get() - T& get() - { - return const_cast<T&>(const_cast<const LLLazy<T>*>(this)->get()); - } - - /// operator*() is equivalent to get() - const T& operator*() const { return get(); } - /// operator*() is equivalent to get() - T& operator*() { return get(); } - - /** - * operator->() must return (something resembling) T*. It's tempting to - * return the underlying boost::scoped_ptr<T>, but that would require - * breaking out the lazy-instantiation logic from get() into a common - * private method. Assume the pointer used for operator->() access is very - * short-lived. - */ - const T* operator->() const { return &get(); } - /// non-const operator->() - T* operator->() { return &get(); } - - /// set(Factory). This will throw InstanceChange if mInstance has already - /// been set. - void set(const Factory& factory) - { - ensureNoInstance(mInstance); - mFactory = factory; - } - - /// set(T*). This will throw InstanceChange if mInstance has already been - /// set. - void set(T* instance) - { - ensureNoInstance(mInstance); - mInstance.reset(instance); - } - -private: - Factory mFactory; - // Consider an LLLazy<T> member of a class we're accessing by const - // reference. We want to allow even const methods to touch the LLLazy<T> - // member. Hence the actual pointer must be mutable because such access - // might assign it. - mutable boost::scoped_ptr<T> mInstance; -}; - -#if (! defined(__GNUC__)) || (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3) -// Not gcc at all, or a gcc more recent than gcc 3.3 -#define GCC33 0 -#else -#define GCC33 1 -#endif - -/** - * LLLazyBase<T> wraps LLLazy<T>, giving you an alternative way to replace - * <tt>Inner mInner;</tt>. Instead of coding <tt>LLLazy<Inner> mInner</tt>, - * you can add LLLazyBase<Inner> to your Outer class's bases, e.g.: - * @code - * class Outer: public LLLazyBase<Inner> - * { - * ... - * }; - * @endcode - * - * This gives you @c public get() and @c protected set() methods without - * having to make your LLLazy<Inner> member @c protected. The tradeoff is that - * you must access the wrapped LLLazy<Inner> using get() and set() rather than - * with <tt>operator*()</tt> or <tt>operator->()</tt>. - * - * This mechanism can be used for more than one member, but only if they're of - * different types. That is, you can replace: - * @code - * DifficultClass mDifficult; - * AwkwardType mAwkward; - * @endcode - * with: - * @code - * class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType> - * { - * ... - * }; - * @endcode - * but for a situation like this: - * @code - * DifficultClass mMainDifficult, mAuxDifficult; - * @endcode - * you should directly embed LLLazy<DifficultClass> (q.v.). - * - * For multiple LLLazyBase bases, e.g. the <tt>LLLazyBase<DifficultClass>, - * LLLazyBase<AwkwardType></tt> example above, access the relevant get()/set() - * as (e.g.) <tt>LLLazyBase<DifficultClass>::get()</tt>. (This is why you - * can't have multiple LLLazyBase<T> of the same T.) For a bit of syntactic - * sugar, please see getLazy()/setLazy(). - */ -template <typename T> -class LLLazyBase -{ -public: - /// invoke default LLLazy constructor - LLLazyBase() {} - /// make wrapped LLLazy bind an explicit Factory - LLLazyBase(const typename LLLazy<T>::Factory& factory): - mInstance(factory) - {} - - /// access to LLLazy::get() - T& get() { return *mInstance; } - /// access to LLLazy::get() - const T& get() const { return *mInstance; } - -protected: - // see getLazy()/setLazy() - #if (! GCC33) - template <typename T2, class MYCLASS> friend T2& getLazy(MYCLASS* this_); - template <typename T2, class MYCLASS> friend const T2& getLazy(const MYCLASS* this_); - #else // gcc 3.3 - template <typename T2, class MYCLASS> friend T2& getLazy(const MYCLASS* this_); - #endif // gcc 3.3 - template <typename T2, class MYCLASS> friend void setLazy(MYCLASS* this_, T2* instance); - template <typename T2, class MYCLASS> - friend void setLazy(MYCLASS* this_, const typename LLLazy<T2>::Factory& factory); - - /// access to LLLazy::set(Factory) - void set(const typename LLLazy<T>::Factory& factory) - { - mInstance.set(factory); - } - - /// access to LLLazy::set(T*) - void set(T* instance) - { - mInstance.set(instance); - } - -private: - LLLazy<T> mInstance; -}; - -/** - * @name getLazy()/setLazy() - * Suppose you have something like the following: - * @code - * class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType> - * { - * ... - * }; - * @endcode - * - * Your methods can reference the @c DifficultClass instance using - * <tt>LLLazyBase<DifficultClass>::get()</tt>, which is admittedly a bit ugly. - * Alternatively, you can write <tt>getLazy<DifficultClass>(this)</tt>, which - * is somewhat more straightforward to read. - * - * Similarly, - * @code - * LLLazyBase<DifficultClass>::set(new TestDifficultClass()); - * @endcode - * could instead be written: - * @code - * setLazy<DifficultClass>(this, new TestDifficultClass()); - * @endcode - * - * @note - * I wanted to provide getLazy() and setLazy() without explicitly passing @c - * this. That would imply making them methods on a base class rather than free - * functions. But if <tt>LLLazyBase<T></tt> derives normally from (say) @c - * LLLazyGrandBase providing those methods, then unqualified getLazy() would - * be ambiguous: you'd have to write <tt>LLLazyBase<T>::getLazy<T>()</tt>, - * which is even uglier than <tt>LLLazyBase<T>::get()</tt>, and therefore - * pointless. You can make the compiler not care which @c LLLazyGrandBase - * instance you're talking about by making @c LLLazyGrandBase a @c virtual - * base class of @c LLLazyBase. But in that case, - * <tt>LLLazyGrandBase::getLazy<T>()</tt> can't access - * <tt>LLLazyBase<T>::get()</tt>! - * - * We want <tt>getLazy<T>()</tt> to access <tt>LLLazyBase<T>::get()</tt> as if - * in the lexical context of some subclass method. Ironically, free functions - * let us do that better than methods on a @c virtual base class -- but that - * implies passing @c this explicitly. So be it. - */ -//@{ -#if (! GCC33) -template <typename T, class MYCLASS> -T& getLazy(MYCLASS* this_) { return this_->LLLazyBase<T>::get(); } -template <typename T, class MYCLASS> -const T& getLazy(const MYCLASS* this_) { return this_->LLLazyBase<T>::get(); } -#else // gcc 3.3 -// For const-correctness, we really should have two getLazy() variants: one -// accepting const MYCLASS* and returning const T&, the other accepting -// non-const MYCLASS* and returning non-const T&. This works fine on the Mac -// (gcc 4.0.1) and Windows (MSVC 8.0), but fails on our Linux 32-bit Debian -// Sarge stations (gcc 3.3.5). Since I really don't know how to beat that aging -// compiler over the head to make it do the right thing, I'm going to have to -// move forward with the wrong thing: a single getLazy() function that accepts -// const MYCLASS* and returns non-const T&. -template <typename T, class MYCLASS> -T& getLazy(const MYCLASS* this_) { return const_cast<MYCLASS*>(this_)->LLLazyBase<T>::get(); } -#endif // gcc 3.3 -template <typename T, class MYCLASS> -void setLazy(MYCLASS* this_, T* instance) { this_->LLLazyBase<T>::set(instance); } -template <typename T, class MYCLASS> -void setLazy(MYCLASS* this_, const typename LLLazy<T>::Factory& factory) -{ - this_->LLLazyBase<T>::set(factory); -} -//@} - -#endif /* ! defined(LL_LLLAZY_H) */ diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index 0a57ef1c48..84d2a12f65 100755 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -394,7 +394,7 @@ public: LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN)); LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD nop; - F64 until(LLTimer::getElapsedSeconds() + 2); + F64 until = (LLTimer::getElapsedSeconds() + 2).value(); while (childin.size() && LLTimer::getElapsedSeconds() < until) { mainloop.post(nop); diff --git a/indra/llcommon/lllocalidhashmap.h b/indra/llcommon/lllocalidhashmap.h deleted file mode 100755 index 8f4f91a560..0000000000 --- a/indra/llcommon/lllocalidhashmap.h +++ /dev/null @@ -1,895 +0,0 @@ -/** - * @file lllocalidhashmap.h - * @brief Map specialized for dealing with local ids - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLLOCALIDHASHMAP_H -#define LL_LLLOCALIDHASHMAP_H - -#include "stdtypes.h" -#include "llerror.h" - -const S32 MAX_ITERS = 4; -// LocalID hash map - -// -// LLLocalIDHashNode -// - -template <class DATA, int SIZE> -class LLLocalIDHashNode -{ -public: - LLLocalIDHashNode(); - -public: - S32 mCount; - U32 mKey[SIZE]; - DATA mData[SIZE]; - LLLocalIDHashNode<DATA, SIZE> *mNextNodep; -}; - - -// -// LLLocalIDHashNode implementation -// -template <class DATA, int SIZE> -LLLocalIDHashNode<DATA, SIZE>::LLLocalIDHashNode() -{ - mCount = 0; - mNextNodep = NULL; -} - -// -// LLLocalIDHashMapIter -// -template <class DATA_TYPE, int SIZE> -class LLLocalIDHashMap; - -template <class DATA_TYPE, int SIZE> -class LLLocalIDHashMapIter -{ -public: - LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp); - ~LLLocalIDHashMapIter(); - - void setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp); - inline void first(); - inline void next(); - inline DATA_TYPE& current(); // *NOTE: Deprecate? Phoenix 2005-04-15 - inline BOOL done() const; - inline S32 currentBin() const; - inline void setBin(S32 bin); - - DATA_TYPE& operator*() const - { - return mCurHashNodep->mData[mCurHashNodeKey]; - } - DATA_TYPE* operator->() const - { - return &(operator*()); - } - - LLLocalIDHashMap<DATA_TYPE, SIZE> *mHashMapp; - LLLocalIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep; - - S32 mCurHashMapNodeNum; - S32 mCurHashNodeKey; - - DATA_TYPE mNull; - - S32 mIterID; -}; - - - -template <class DATA_TYPE, int SIZE> -class LLLocalIDHashMap -{ -public: - friend class LLLocalIDHashMapIter<DATA_TYPE, SIZE>; - - LLLocalIDHashMap(); // DO NOT use this unless you explicitly setNull, or the data type constructs a "null" - // object by default - // basic constructor including sorter - LLLocalIDHashMap(const DATA_TYPE &null_data); - // Hack, this should really be a const ref, but I'm not doing it that way because the sim - // usually uses pointers. - ~LLLocalIDHashMap(); - - inline DATA_TYPE &get(const U32 local_id); - inline BOOL check(const U32 local_id) const; - inline DATA_TYPE &set(const U32 local_id, const DATA_TYPE data); - inline BOOL remove(const U32 local_id); - void removeAll(); - - void setNull(const DATA_TYPE data) { mNull = data; } - - inline S32 getLength() const; // Warning, NOT O(1!) - - void dumpIter(); - void dumpBin(U32 bin); - -protected: - // Only used by the iterator. - void addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter); - void removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter); - - // Remove the item and shift all items afterward down the list, - // fixing up iterators as we go. - BOOL removeWithShift(const U32 local_id); - -protected: - LLLocalIDHashNode<DATA_TYPE, SIZE> mNodes[256]; - - S32 mIterCount; - LLLocalIDHashMapIter<DATA_TYPE, SIZE> *mIters[MAX_ITERS]; - - DATA_TYPE mNull; -}; - - -// -// LLLocalIDHashMap implementation -// - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap() -: mIterCount(0), - mNull() -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - mIters[i] = NULL; - } -} - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap(const DATA_TYPE &null_data) -: mIterCount(0), - mNull(null_data) -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - mIters[i] = NULL; - } -} - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMap<DATA_TYPE, SIZE>::~LLLocalIDHashMap() -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i]) - { - mIters[i]->mHashMapp = NULL; - mIterCount--; - } - } - removeAll(); -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeAll() -{ - S32 bin; - for (bin = 0; bin < 256; bin++) - { - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - - BOOL first = TRUE; - do // First node guaranteed to be there - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - nodep->mData[i] = mNull; - } - - nodep->mCount = 0; - // Done with all objects in this node, go to the next. - - LLLocalIDHashNode<DATA_TYPE, SIZE>* curp = nodep; - nodep = nodep->mNextNodep; - - // Delete the node if it's not the first node - if (first) - { - first = FALSE; - curp->mNextNodep = NULL; - } - else - { - delete curp; - } - } while (nodep); - } -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpIter() -{ - std::cout << "Hash map with " << mIterCount << " iterators" << std::endl; - - std::cout << "Hash Map Iterators:" << std::endl; - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i]) - { - llinfos << i << " " << mIters[i]->mCurHashNodep << " " << mIters[i]->mCurHashNodeKey << llendl; - } - else - { - llinfos << i << "null" << llendl; - } - } -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpBin(U32 bin) -{ - std::cout << "Dump bin " << bin << std::endl; - - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - S32 node = 0; - do // First node guaranteed to be there. - { - std::cout << "Bin " << bin - << " node " << node - << " count " << nodep->mCount - << " contains " << std::flush; - - S32 i; - for (i = 0; i < nodep->mCount; i++) - { - std::cout << nodep->mData[i] << " " << std::flush; - } - - std::cout << std::endl; - - nodep = nodep->mNextNodep; - node++; - } while (nodep); -} - -template <class DATA_TYPE, int SIZE> -inline S32 LLLocalIDHashMap<DATA_TYPE, SIZE>::getLength() const -{ - S32 count = 0; - S32 bin; - for (bin = 0; bin < 256; bin++) - { - const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - while (nodep) - { - count += nodep->mCount; - nodep = nodep->mNextNodep; - } - } - return count; -} - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::get(const U32 local_id) -{ - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff]; - - do // First node guaranteed to be there - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // We found it. - return nodep->mData[i]; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } while (nodep); - - return mNull; -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::check(const U32 local_id) const -{ - const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff]; - - do // First node guaranteed to be there - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // We found it. - return TRUE; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } while (nodep); - - // Didn't find anything - return FALSE; -} - - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::set(const U32 local_id, const DATA_TYPE data) -{ - // Set is just like a normal find, except that if we find a match - // we replace it with the input value. - // If we don't find a match, we append to the end of the list. - - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff]; - - while (1) - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // We found a match for this key, replace the data with - // the incoming data. - nodep->mData[i] = data; - return nodep->mData[i]; - } - } - if (!nodep->mNextNodep) - { - // We've iterated through all of the keys without finding a match - if (i < SIZE) - { - // There's still some space on this node, append - // the key and data to it. - nodep->mKey[i] = local_id; - nodep->mData[i] = data; - nodep->mCount++; - - return nodep->mData[i]; - } - else - { - // This node is full, append a new node to the end. - nodep->mNextNodep = new LLLocalIDHashNode<DATA_TYPE, SIZE>; - nodep->mNextNodep->mKey[0] = local_id; - nodep->mNextNodep->mData[0] = data; - nodep->mNextNodep->mCount = 1; - - return nodep->mNextNodep->mData[0]; - } - } - - // No match on this node, go to the next - nodep = nodep->mNextNodep; - } -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::remove(const U32 local_id) -{ - // Remove is the trickiest operation. - // What we want to do is swap the last element of the last - // node if we find the one that we want to remove, but we have - // to deal with deleting the node from the tail if it's empty, but - // NOT if it's the only node left. - - const S32 node_index = local_id & 0xff; - - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index]; - - // A modification of the standard search algorithm. - do // First node guaranteed to be there - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // If we're removing the item currently pointed to by one - // or more iterators, we can just swap in the last item - // and back the iterator(s) up by one. - // Otherwise, we need to do a slow and safe shift of all - // items back to one position to fill the hole and fix up - // all iterators we find. - BOOL need_shift = FALSE; - S32 cur_iter; - if (mIterCount) - { - for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++) - { - if (mIters[cur_iter]) - { - // We only care if the hash map node is on the one - // that we're working on. If it's before, we've already - // traversed it, if it's after, changing the order doesn't - // matter. - if (mIters[cur_iter]->mCurHashMapNodeNum == node_index) - { - if ((mIters[cur_iter]->mCurHashNodep == nodep) - && (mIters[cur_iter]->mCurHashNodeKey == i)) - { - // it's on the one we're deleting, we'll - // fix the iterator quickly below. - } - else - { - // We're trying to remove an item on this - // iterator's chain that this - // iterator doesn't point to! We need to do - // the slow remove-and-shift-down case. - need_shift = TRUE; - } - } - } - } - } - - // Removing an item that isn't pointed to by all iterators - if (need_shift) - { - return removeWithShift(local_id); - } - - // Fix the iterators that point to this node/i pair, the - // one we're deleting - for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++) - { - if (mIters[cur_iter]) - { - // We only care if the hash map node is on the one - // that we're working on. If it's before, we've already - // traversed it, if it's after, changing the order doesn't - // matter. - if (mIters[cur_iter]->mCurHashMapNodeNum == node_index) - { - if ((mIters[cur_iter]->mCurHashNodep == nodep) - && (mIters[cur_iter]->mCurHashNodeKey == i)) - { - // We can handle the case where we're deleting - // the element we're on trivially (sort of). - if (nodep->mCount > 1) - { - // If we're not going to delete this node, - // it's OK. - mIters[cur_iter]->mCurHashNodeKey--; - } - else - { - // We're going to delete this node, because this - // is the last element on it. - - // Find the next node, and then back up one. - mIters[cur_iter]->next(); - mIters[cur_iter]->mCurHashNodeKey--; - } - } - } - } - } - - // We found the node that we want to remove. - // Find the last (and next-to-last) node, and the index of the last - // element. We could conceviably start from the node we're on, - // but that makes it more complicated, this is easier. - - LLLocalIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[node_index]; - LLLocalIDHashNode<DATA_TYPE, SIZE> *lastp = prevp; - - // Find the last and next-to-last - while (lastp->mNextNodep) - { - prevp = lastp; - lastp = lastp->mNextNodep; - } - - // First, swap in the last to the current location. - nodep->mKey[i] = lastp->mKey[lastp->mCount - 1]; - nodep->mData[i] = lastp->mData[lastp->mCount - 1]; - - // Now, we delete the entry - lastp->mCount--; - lastp->mData[lastp->mCount] = mNull; - - if (!lastp->mCount) - { - // We deleted the last element! - if (lastp != &mNodes[local_id & 0xff]) - { - // Only blitz the node if it's not the head - // Set the previous node to point to NULL, then - // blitz the empty last node - prevp->mNextNodep = NULL; - delete lastp; - } - } - - return TRUE; - } - } - - // Iterate to the next node, we've scanned all the entries in this one. - nodep = nodep->mNextNodep; - } while (nodep); - - return FALSE; -} - -template <class DATA_TYPE, int SIZE> -BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::removeWithShift(const U32 local_id) -{ - const S32 node_index = local_id & 0xFF; - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index]; - LLLocalIDHashNode<DATA_TYPE, SIZE>* prevp = NULL; - BOOL found = FALSE; - - do // First node guaranteed to be there - { - const S32 count = nodep->mCount; - S32 i; - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // Found the item. Start shifting items from later - // in the list over this item. - found = TRUE; - } - - if (found) - { - // If there is an iterator on this node, we need to - // back it up. - S32 cur_iter; - for (cur_iter = 0; cur_iter <MAX_ITERS; cur_iter++) - { - LLLocalIDHashMapIter<DATA_TYPE, SIZE>* iter; - iter = mIters[cur_iter]; - // If an iterator is on this node,i pair, then back it up. - if (iter - && iter->mCurHashMapNodeNum == node_index - && iter->mCurHashNodep == nodep - && iter->mCurHashNodeKey == i) - { - if (i > 0) - { - // Don't need to move iterator nodep, since - // we're in the same node. - iter->mCurHashNodeKey--; - } - else if (prevp) - { - // need to go the previous node, last item - iter->mCurHashNodep = prevp; - iter->mCurHashNodeKey = prevp->mCount - 1; - } - else - { - // we're on the first item in the list, but - // need to go back anyhow. - - // BUG: If this deletion empties the list, - // iter->done() will be wrong until - // iter->next() is called. - iter->mCurHashNodeKey = -1; - } - } - } - - // Copy data from the next position into this position. - if (i < count-1) - { - // we're not on the last item in the node, - // so we can copy within the node - nodep->mKey[i] = nodep->mKey[i+1]; - nodep->mData[i] = nodep->mData[i+1]; - } - else if (nodep->mNextNodep) - { - // we're on the last item in the node, - // but there's a next node we can copy from - nodep->mKey[i] = nodep->mNextNodep->mKey[0]; - nodep->mData[i] = nodep->mNextNodep->mData[0]; - } - else - { - // We're on the last position in the list. - // No one to copy from. Replace with nothing. - nodep->mKey[i] = 0; - nodep->mData[i] = mNull; - } - } - } - - // Last node in chain, so delete the last node - if (found - && !nodep->mNextNodep) - { - // delete the last item off the last node - nodep->mCount--; - - if (nodep->mCount == 0) - { - // We deleted the last element! - if (nodep != &mNodes[node_index]) - { - // Always have a prevp if we're not the head. - llassert(prevp); - - // Only blitz the node if it's not the head - // Set the previous node to point to NULL, then - // blitz the empty last node - prevp->mNextNodep = NULL; - delete nodep; - nodep = NULL; - } - } - - // Deleted last item in chain, so we're done. - return found; - } - - prevp = nodep; - nodep = nodep->mNextNodep; - } while (nodep); - - return found; -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter) -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i] == iter) - { - mIters[i] = NULL; - mIterCount--; - return; - } - } - llerrs << "Iterator " << iter << " not found for removal in hash map!" << llendl; -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter) -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i] == NULL) - { - mIters[i] = iter; - mIterCount++; - return; - } - } - llerrs << "More than " << MAX_ITERS << " iterating over a map simultaneously!" << llendl; -} - - - -// -// LLLocalIDHashMapIter Implementation -// -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMapIter<DATA_TYPE, SIZE>::LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp) -{ - mHashMapp = NULL; - setMap(hash_mapp); -} - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMapIter<DATA_TYPE, SIZE>::~LLLocalIDHashMapIter() -{ - if (mHashMapp) - { - mHashMapp->removeIter(this); - } -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp) -{ - if (mHashMapp) - { - mHashMapp->removeIter(this); - } - mHashMapp = hash_mapp; - if (mHashMapp) - { - mHashMapp->addIter(this); - } - - mCurHashNodep = NULL; - mCurHashMapNodeNum = -1; - mCurHashNodeKey = 0; -} - -template <class DATA_TYPE, int SIZE> -inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::first() -{ - // Iterate through until we find the first non-empty node; - S32 i; - for (i = 0; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // Completely empty! - mCurHashNodep = NULL; - //return mNull; - return; -} - -template <class DATA_TYPE, int SIZE> -inline BOOL LLLocalIDHashMapIter<DATA_TYPE, SIZE>::done() const -{ - return mCurHashNodep ? FALSE : TRUE; -} - -template <class DATA_TYPE, int SIZE> -inline S32 LLLocalIDHashMapIter<DATA_TYPE, SIZE>::currentBin() const -{ - if ( (mCurHashMapNodeNum > 255) - ||(mCurHashMapNodeNum < 0)) - { - return 0; - } - else - { - return mCurHashMapNodeNum; - } -} - -template <class DATA_TYPE, int SIZE> -inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setBin(S32 bin) -{ - // Iterate through until we find the first non-empty node; - S32 i; - bin = llclamp(bin, 0, 255); - for (i = bin; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - return; - } - } - for (i = 0; i < bin; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - return; - } - } - // Completely empty! - mCurHashNodep = NULL; -} - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLLocalIDHashMapIter<DATA_TYPE, SIZE>::current() -{ - if (!mCurHashNodep) - { - return mNull; - } - return mCurHashNodep->mData[mCurHashNodeKey]; -} - -template <class DATA_TYPE, int SIZE> -inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::next() -{ - // No current entry, this iterator is done - if (!mCurHashNodep) - { - //return mNull; - return; - } - - // Go to the next element - mCurHashNodeKey++; - if (mCurHashNodeKey < mCurHashNodep->mCount) - { - // We're not done with this node, return the current element - //return mCurHashNodep->mData[mCurHashNodeKey]; - return; - } - - // Done with this node, move to the next - mCurHashNodep = mCurHashNodep->mNextNodep; - if (mCurHashNodep) - { - // Return the first element - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - - // Find the next non-empty node (keyed on the first byte) - mCurHashMapNodeNum++; - - S32 i; - for (i = mCurHashMapNodeNum; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - // We found one that wasn't empty - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // OK, we're done, nothing else to iterate - mCurHashNodep = NULL; - mHashMapp->mIterCount--; // Decrement since we're safe to do removes now - //return mNull; - return; -} - -#endif // LL_LLLOCALIDHASHMAP_H diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index 1409c55d1c..ed80af36d8 100755 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -76,7 +76,6 @@ documentation and/or software. #include "llmd5.h" -#include <cassert> #include <iostream> // cerr // how many bytes to grab at a time when checking files diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 70ad10ad55..c6b02df939 100755 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -32,7 +32,6 @@ //#endif #if defined(LL_WINDOWS) -//# include <windows.h> # include <psapi.h> #elif defined(LL_DARWIN) # include <sys/types.h> diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index e725bdd9fa..95500753e4 100755 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -27,6 +27,9 @@ #define LLMEMORY_H #include "linden_common.h" +#if !LL_WINDOWS +#include <stdint.h> +#endif class LLMutex ; @@ -36,6 +39,20 @@ class LLMutex ; #define LL_CHECK_MEMORY #endif +#if LL_WINDOWS +#define LL_ALIGN_OF __alignof +#else +#define LL_ALIGN_OF __align_of__ +#endif + +#if LL_WINDOWS +#define LL_DEFAULT_HEAP_ALIGN 8 +#elif LL_DARWIN +#define LL_DEFAULT_HEAP_ALIGN 16 +#elif LL_LINUX +#define LL_DEFAULT_HEAP_ALIGN 8 +#endif + inline void* ll_aligned_malloc( size_t size, int align ) { void* mem = malloc( size + (align - 1) + sizeof(void*) ); diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp index 731e58bd20..fd89cb818a 100755 --- a/indra/llcommon/llmetricperformancetester.cpp +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -29,9 +29,9 @@ #include "indra_constants.h" #include "llerror.h" #include "llsdserialize.h" -#include "llstat.h" #include "lltreeiterators.h" #include "llmetricperformancetester.h" +#include "llfasttimer.h" //---------------------------------------------------------------------------------------------- // LLMetricPerformanceTesterBasic : static methods and testers management @@ -91,7 +91,7 @@ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::s // Return TRUE if this metric is requested or if the general default "catch all" metric is requested BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name) { - return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME))); + return (LLTrace::TimeBlock::sMetricLog && ((LLTrace::TimeBlock::sLogName == name) || (LLTrace::TimeBlock::sLogName == DEFAULT_METRIC_NAME))); } /*static*/ @@ -194,8 +194,7 @@ void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd) { - LLMutexLock lock(LLFastTimer::sLogLock); - LLFastTimer::sLogQueue.push((*sd)); + LLTrace::TimeBlock::pushLog(*sd); } void LLMetricPerformanceTesterBasic::outputTestResults() diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h index 319955ef93..9517e2db5e 100755 --- a/indra/llcommon/llmortician.h +++ b/indra/llcommon/llmortician.h @@ -28,6 +28,7 @@ #define LLMORTICIAN_H #include "stdtypes.h" +#include <list> class LL_COMMON_API LLMortician { diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp new file mode 100644 index 0000000000..ad0287c6d5 --- /dev/null +++ b/indra/llcommon/llmutex.cpp @@ -0,0 +1,179 @@ +/** + * @file llmutex.cpp + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llapr.h" + +#include "apr_portable.h" + +#include "llmutex.h" +#include "llthread.h" + +//============================================================================ + +LLMutex::LLMutex(apr_pool_t *poolp) : + mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) +{ + //if (poolp) + //{ + // mIsLocalPool = FALSE; + // mAPRPoolp = poolp; + //} + //else + { + mIsLocalPool = TRUE; + apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread + } + apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); +} + + +LLMutex::~LLMutex() +{ +#if MUTEX_DEBUG + //bad assertion, the subclass LLSignal might be "locked", and that's OK + //llassert_always(!isLocked()); // better not be locked! +#endif + if (ll_apr_is_initialized()) + { + apr_thread_mutex_destroy(mAPRMutexp); + if (mIsLocalPool) + { + apr_pool_destroy(mAPRPoolp); + } + } + mAPRMutexp = NULL; +} + + +void LLMutex::lock() +{ + if(isSelfLocked()) + { //redundant lock + mCount++; + return; + } + + apr_thread_mutex_lock(mAPRMutexp); + +#if MUTEX_DEBUG + // Have to have the lock before we can access the debug info + U32 id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + llerrs << "Already locked in Thread: " << id << llendl; + mIsLocked[id] = TRUE; +#endif + + mLockingThread = LLThread::currentID(); +} + +void LLMutex::unlock() +{ + if (mCount > 0) + { //not the root unlock + mCount--; + return; + } + +#if MUTEX_DEBUG + // Access the debug info while we have the lock + U32 id = LLThread::currentID(); + if (mIsLocked[id] != TRUE) + llerrs << "Not locked in Thread: " << id << llendl; + mIsLocked[id] = FALSE; +#endif + + mLockingThread = NO_THREAD; + apr_thread_mutex_unlock(mAPRMutexp); +} + +bool LLMutex::isLocked() +{ + apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); + if (APR_STATUS_IS_EBUSY(status)) + { + return true; + } + else + { + apr_thread_mutex_unlock(mAPRMutexp); + return false; + } +} + +bool LLMutex::isSelfLocked() +{ + return mLockingThread == LLThread::currentID(); +} + +U32 LLMutex::lockingThread() const +{ + return mLockingThread; +} + +//============================================================================ + +LLCondition::LLCondition(apr_pool_t *poolp) : + LLMutex(poolp) +{ + // base class (LLMutex) has already ensured that mAPRPoolp is set up. + + apr_thread_cond_create(&mAPRCondp, mAPRPoolp); +} + + +LLCondition::~LLCondition() +{ + apr_thread_cond_destroy(mAPRCondp); + mAPRCondp = NULL; +} + + +void LLCondition::wait() +{ + if (!isLocked()) + { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait + apr_thread_mutex_lock(mAPRMutexp); +#if MUTEX_DEBUG + // avoid asserts on destruction in non-release builds + U32 id = LLThread::currentID(); + mIsLocked[id] = TRUE; +#endif + } + apr_thread_cond_wait(mAPRCondp, mAPRMutexp); +} + +void LLCondition::signal() +{ + apr_thread_cond_signal(mAPRCondp); +} + +void LLCondition::broadcast() +{ + apr_thread_cond_broadcast(mAPRCondp); +} + + +//============================================================================ diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h new file mode 100644 index 0000000000..cbde4c47a9 --- /dev/null +++ b/indra/llcommon/llmutex.h @@ -0,0 +1,101 @@ +/** + * @file llmutex.h + * @brief Base classes for mutex and condition handling. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMUTEX_H +#define LL_LLMUTEX_H + +#include "llapr.h" +#include "apr_thread_cond.h" + +//============================================================================ + +#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) + +class LL_COMMON_API LLMutex +{ +public: + typedef enum + { + NO_THREAD = 0xFFFFFFFF + } e_locking_thread; + + LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex + virtual ~LLMutex(); + + void lock(); // blocks + void unlock(); + bool isLocked(); // non-blocking, but does do a lock/unlock so not free + bool isSelfLocked(); //return true if locked in a same thread + U32 lockingThread() const; //get ID of locking thread + +protected: + apr_thread_mutex_t *mAPRMutexp; + mutable U32 mCount; + mutable U32 mLockingThread; + + apr_pool_t *mAPRPoolp; + BOOL mIsLocalPool; + +#if MUTEX_DEBUG + std::map<U32, BOOL> mIsLocked; +#endif +}; + +// Actually a condition/mutex pair (since each condition needs to be associated with a mutex). +class LL_COMMON_API LLCondition : public LLMutex +{ +public: + LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. + ~LLCondition(); + + void wait(); // blocks + void signal(); + void broadcast(); + +protected: + apr_thread_cond_t *mAPRCondp; +}; + +class LLMutexLock +{ +public: + LLMutexLock(LLMutex* mutex) + { + mMutex = mutex; + + if(mMutex) + mMutex->lock(); + } + ~LLMutexLock() + { + if(mMutex) + mMutex->unlock(); + } +private: + LLMutex* mMutex; +}; + +#endif // LL_LLTHREAD_H diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 88c09c8dca..6a0a8fcb0d 100755 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -97,24 +97,13 @@ public: LLPointer<Type>& operator =(Type* ptr) { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - + assign(ptr); return *this; } LLPointer<Type>& operator =(const LLPointer<Type>& ptr) { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } + assign(ptr); return *this; } @@ -122,12 +111,7 @@ public: template<typename Subclass> LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr) { - if( mPointer != ptr.get() ) - { - unref(); - mPointer = ptr.get(); - ref(); - } + assign(ptr.get()); return *this; } @@ -144,6 +128,16 @@ protected: void ref(); void unref(); #else + + void assign(const LLPointer<Type>& ptr) + { + if( mPointer != ptr.mPointer ) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + } void ref() { if (mPointer) @@ -156,9 +150,9 @@ protected: { if (mPointer) { - Type *tempp = mPointer; + Type *temp = mPointer; mPointer = NULL; - tempp->unref(); + temp->unref(); if (mPointer != NULL) { llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; @@ -171,4 +165,40 @@ protected: Type* mPointer; }; +template<typename Type> +class LLCopyOnWritePointer : public LLPointer<Type> +{ +public: + typedef LLCopyOnWritePointer<Type> self_t; + typedef LLPointer<Type> pointer_t; + + LLCopyOnWritePointer() + {} + + LLCopyOnWritePointer(Type* ptr) + : LLPointer<Type>(ptr) + {} + + LLCopyOnWritePointer(LLPointer<Type>& ptr) + : LLPointer<Type>(ptr) + {} + + Type* write() + { + makeUnique(); + return pointer_t::mPointer; + } + + void makeUnique() + { + if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) + { + *(pointer_t* )(this) = new Type(*pointer_t::mPointer); + } + } + + const Type* operator->() const { return pointer_t::mPointer; } + const Type& operator*() const { return *pointer_t::mPointer; } +}; + #endif diff --git a/indra/llcommon/lllazy.cpp b/indra/llcommon/llpredicate.cpp index 29fa040387..1278948e24 100755..100644 --- a/indra/llcommon/lllazy.cpp +++ b/indra/llcommon/llpredicate.cpp @@ -1,10 +1,8 @@ -/** - * @file lllazy.cpp - * @author Nat Goodspeed - * @date 2009-01-28 - * @brief Implementation for lllazy. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ +/** + * @file llpredicate.cpp + * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -25,16 +23,19 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -// Precompiled header #include "linden_common.h" -// associated header -#include "lllazy.h" -// STL headers -// std headers -// external library headers -// other Linden headers -// lllazy.h is presently header-only. This file exists only because our CMake -// test macro ADD_BUILD_TEST requires it. -int dummy = 0; +#include "llpredicate.h" + +namespace LLPredicate +{ + const U32 cPredicateFlagsFromEnum[5] = + { + 0xAAAAaaaa, // 10101010101010101010101010101010 + 0xCCCCcccc, // 11001100110011001100110011001100 + 0xF0F0F0F0, // 11110000111100001111000011110000 + 0xFF00FF00, // 11111111000000001111111100000000 + 0xFFFF0000 // 11111111111111110000000000000000 + }; +} + diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h new file mode 100644 index 0000000000..a0e970a799 --- /dev/null +++ b/indra/llcommon/llpredicate.h @@ -0,0 +1,210 @@ +/** + * @file llpredicate.h + * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPREDICATE_H +#define LL_LLPREDICATE_H + +#include "llerror.h" + +namespace LLPredicate +{ + template<typename ENUM> class Rule; + + extern const U32 cPredicateFlagsFromEnum[5]; + + template<typename ENUM> + class Value + { + public: + typedef U32 predicate_flag_t; + static const S32 cMaxEnum = 5; + + Value(ENUM e, bool predicate_value = true) + : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e]) + { + llassert(0 <= e && e < cMaxEnum); + } + + Value() + : mPredicateFlags(0xFFFFffff) + {} + + Value operator!() const + { + Value new_value; + new_value.mPredicateFlags = ~mPredicateFlags; + return new_value; + } + + Value operator &&(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags; + return new_value; + } + + Value operator ||(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags; + return new_value; + } + + void set(ENUM e, bool value = true) + { + llassert(0 <= e && e < cMaxEnum); + predicate_flag_t flags_to_modify; + predicate_flag_t mask = cPredicateFlagsFromEnum[e]; + if (value) + { // add predicate "e" to flags that don't contain it already + flags_to_modify = (mPredicateFlags & ~mask); + // clear flags not containing e + mPredicateFlags &= mask; + // add back flags shifted to contain e + mPredicateFlags |= flags_to_modify << (0x1 << e); + } + else + { // remove predicate "e" from flags that contain it + flags_to_modify = (mPredicateFlags & mask); + // clear flags containing e + mPredicateFlags &= ~mask; + // add back flags shifted to not contain e + mPredicateFlags |= flags_to_modify >> (0x1 << e); + } + } + + void forget(ENUM e) + { + set(e, true); + U32 flags_with_predicate = mPredicateFlags; + set(e, false); + // ambiguous value is result of adding and removing predicate at the same time! + mPredicateFlags |= flags_with_predicate; + } + + bool allSet() const + { + return mPredicateFlags == ~0; + } + + bool noneSet() const + { + return mPredicateFlags == 0; + } + + bool someSet() const + { + return mPredicateFlags != 0; + } + + private: + predicate_flag_t mPredicateFlags; + }; + + template<typename ENUM> + class Rule + { + public: + Rule(ENUM value) + : mRule(value) + {} + + Rule(const Value<ENUM> other) + : mRule(other) + {} + + Rule() + {} + + void require(ENUM e) + { + mRule.set(e, require); + } + + void allow(ENUM e) + { + mRule.forget(e); + } + + bool check(const Value<ENUM> value) const + { + return (mRule && value).someSet(); + } + + bool requires(const Value<ENUM> value) const + { + return (mRule && value).someSet() && (!mRule && value).noneSet(); + } + + bool isAmbivalent(const Value<ENUM> value) const + { + return (mRule && value).someSet() && (!mRule && value).someSet(); + } + + bool acceptsAll() const + { + return mRule.allSet(); + } + + bool acceptsNone() const + { + return mRule.noneSet(); + } + + Rule operator!() const + { + Rule new_rule; + new_rule.mRule = !mRule; + return new_rule; + } + + Rule operator &&(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule && other.mRule; + return new_rule; + } + + Rule operator ||(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule || other.mRule; + return new_rule; + } + + private: + Value<ENUM> mRule; + }; +} + +template<typename ENUM> +LLPredicate::Value<ENUM> ll_make_predicate(ENUM e, bool predicate_value = true) +{ + return LLPredicate::Value<ENUM>(e, predicate_value); +} + + +#endif // LL_LLPREDICATE_H diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index d711ce2f74..43ccadc412 100755 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -29,6 +29,7 @@ #include "llinitparam.h" #include "llsdparam.h" +#include "llwin32headerslean.h" #include "apr_thread_proc.h" #include <boost/shared_ptr.hpp> #include <boost/ptr_container/ptr_vector.hpp> @@ -38,8 +39,7 @@ #include <stdexcept> #if LL_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include <windows.h> // HANDLE (eye roll) +#include "llwin32headerslean.h" // for HANDLE #elif LL_LINUX #if defined(Status) #undef Status diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index fd8f603d21..b80e813d84 100755 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -32,9 +32,7 @@ //#include <memory> #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> +# include "llwin32headerslean.h" # define _interlockedbittestandset _renamed_interlockedbittestandset # define _interlockedbittestandreset _renamed_interlockedbittestandreset # include <intrin.h> @@ -877,7 +875,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL) LLProcessorInfo::~LLProcessorInfo() {} -F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } +LLUnitImplicit<F64, LLUnits::Megahertz> LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); } bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); } bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); } diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 6364d3c8bb..7f220467b0 100755 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -27,6 +27,8 @@ #ifndef LLPROCESSOR_H #define LLPROCESSOR_H +#include "llunit.h" + class LLProcessorInfoImpl; class LL_COMMON_API LLProcessorInfo @@ -35,7 +37,7 @@ public: LLProcessorInfo(); ~LLProcessorInfo(); - F64 getCPUFrequency() const; + LLUnitImplicit<F64, LLUnits::Megahertz> getCPUFrequency() const; bool hasSSE() const; bool hasSSE2() const; bool hasAltivec() const; diff --git a/indra/llcommon/llptrskiplist.h b/indra/llcommon/llptrskiplist.h deleted file mode 100755 index 67c7cde352..0000000000 --- a/indra/llcommon/llptrskiplist.h +++ /dev/null @@ -1,724 +0,0 @@ -/** - * @file llptrskiplist.h - * @brief Skip list implementation. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLPTRSKIPLIST_H -#define LL_LLPTRSKIPLIST_H - -#include "llerror.h" -#include "llrand.h" -//#include "vmath.h" -#include "llrand.h" - -///////////////////////////////////////////// -// -// LLPtrSkipList implementation - skip list for pointers to objects -// - -template <class DATA_TYPE, S32 BINARY_DEPTH = 8> -class LLPtrSkipList -{ -public: - friend class LLPtrSkipNode; - - // basic constructor - LLPtrSkipList(); - // basic constructor including sorter - LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), - BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second)); - ~LLPtrSkipList(); - - inline void setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second)); - inline void setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second)); - - inline BOOL addData(DATA_TYPE *data); - - inline BOOL checkData(const DATA_TYPE *data); - - inline S32 getLength(); // returns number of items in the list - NOT constant time! - - inline BOOL removeData(const DATA_TYPE *data); - - // note that b_sort is ignored - inline BOOL moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort); - - inline BOOL moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort); - - // resort -- use when the value we're sorting by changes - /* IW 12/6/02 - This doesn't work! - Instead, remove the data BEFORE you change it - Then re-insert it after you change it - BOOL resortData(DATA_TYPE *data) - */ - - // remove all nodes from the list but do not delete data - inline void removeAllNodes(); - - inline BOOL deleteData(const DATA_TYPE *data); - - // remove all nodes from the list and delete data - inline void deleteAllData(); - - // place mCurrentp on first node - inline void resetList(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - inline DATA_TYPE *getNextData(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void removeCurrentData(); - - // delete the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getFirstData(); - - // TRUE if nodes are not in sorted order - inline BOOL corrupt(); - -protected: - class LLPtrSkipNode - { - public: - LLPtrSkipNode() - : mData(NULL) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - LLPtrSkipNode(DATA_TYPE *data) - : mData(data) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - ~LLPtrSkipNode() - { - if (mData) - { - llerror("Attempting to call LLPtrSkipNode destructor with a non-null mDatap!", 1); - } - } - - // delete associated data and NULLs out pointer - void deleteData() - { - delete mData; - mData = NULL; - } - - // NULLs out pointer - void removeData() - { - mData = NULL; - } - - DATA_TYPE *mData; - LLPtrSkipNode *mForward[BINARY_DEPTH]; - }; - - static BOOL defaultEquals(const DATA_TYPE *first, const DATA_TYPE *second) - { - return first == second; - } - - - LLPtrSkipNode mHead; - LLPtrSkipNode *mUpdate[BINARY_DEPTH]; - LLPtrSkipNode *mCurrentp; - LLPtrSkipNode *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const DATA_TYPE *first, const DATA_TYPE *second); - BOOL (*mEquals)(const DATA_TYPE *first, const DATA_TYPE *second); -}; - - -// basic constructor -template <class DATA_TYPE, S32 BINARY_DEPTH> -LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList() - : mInsertFirst(NULL), mEquals(defaultEquals) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// basic constructor including sorter -template <class DATA_TYPE, S32 BINARY_DEPTH> -LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), - BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second)) - :mInsertFirst(insert_first), mEquals(equals) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::~LLPtrSkipList() -{ - removeAllNodes(); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second)) -{ - mInsertFirst = insert_first; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second)) -{ - mEquals = equals; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::addData(DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipNode *snode = new LLPtrSkipNode(data); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return TRUE; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mData, data); - } - else - { - return FALSE; - } -} - -// returns number of items in the list -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline S32 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() -{ - U32 length = 0; - for (LLPtrSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - return length; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - current->removeData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// note that b_sort is ignored -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort) -{ - BOOL removed = removeData(data); - BOOL added = newlist->addData(data); - return removed && added; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort) -{ - if (mCurrentOperatingp) - { - mCurrentp = mCurrentOperatingp->mForward[0]; - BOOL removed = removeData(mCurrentOperatingp); - BOOL added = newlist->addData(mCurrentOperatingp); - mCurrentOperatingp = mCurrentp; - return removed && added; - } - return FALSE; -} - -// resort -- use when the value we're sorting by changes -/* IW 12/6/02 - This doesn't work! - Instead, remove the data BEFORE you change it - Then re-insert it after you change it -BOOL resortData(DATA_TYPE *data) -{ - removeData(data); - addData(data); -} -*/ - -// remove all nodes from the list but do not delete data -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes() -{ - LLPtrSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = current->mForward[0]; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = current->mForward[0]; - } - - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - current->deleteData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// remove all nodes from the list and delete data -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteAllData() -{ - LLPtrSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = *mCurrentp->mForward; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = *mCurrentp->mForward; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mData); - } -} - -// delete the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mData); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::corrupt() -{ - LLPtrSkipNode *previous = mHead.mForward[0]; - - // Empty lists are not corrupt. - if (!previous) return FALSE; - - LLPtrSkipNode *current = previous->mForward[0]; - while(current) - { - if (!mInsertFirst(previous->mData, current->mData)) - { - // prev shouldn't be in front of cur! - return TRUE; - } - current = current->mForward[0]; - } - return FALSE; -} - -#endif diff --git a/indra/llcommon/llptrskipmap.h b/indra/llcommon/llptrskipmap.h deleted file mode 100755 index 94bc71ec55..0000000000 --- a/indra/llcommon/llptrskipmap.h +++ /dev/null @@ -1,1239 +0,0 @@ -/** - * @file llptrskipmap.h - * @brief Just like a LLSkipMap, but since it's pointers, you can call - * deleteAllData - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLPTRSKIPMAP_H -#define LL_LLPTRSKIPMAP_H - -#include "llerror.h" -#include "llrand.h" - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH = 8> -class LLPtrSkipMapNode -{ -public: - LLPtrSkipMapNode() - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mIndex; - - for (i = 0; i < (S32)sizeof(INDEX_T); i++) - { - *(zero + i) = 0; - } - - zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_T); i++) - { - *(zero + i) = 0; - } - } - - LLPtrSkipMapNode(const INDEX_T &index) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_T); i++) - { - *(zero + i) = 0; - } - } - - LLPtrSkipMapNode(const INDEX_T &index, DATA_T datap) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - mData = datap; - } - - ~LLPtrSkipMapNode() - { - } - - // delete associated data and NULLs out pointer - void deleteData() - { - delete mData; - mData = 0; - } - - // NULLs out pointer - void removeData() - { - mData = 0; - } - - INDEX_T mIndex; - DATA_T mData; - LLPtrSkipMapNode *mForward[BINARY_DEPTH]; - -private: - // Disallow copying of LLPtrSkipMapNodes by not implementing these methods. - LLPtrSkipMapNode(const LLPtrSkipMapNode &); - LLPtrSkipMapNode &operator=(const LLPtrSkipMapNode &rhs); -}; - -//--------------------------------------------------------------------------- - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH = 8> -class LLPtrSkipMap -{ -public: - typedef BOOL (*compare)(const DATA_T& first, const DATA_T& second); - typedef compare insert_func; - typedef compare equals_func; - - void init(); - - // basic constructor - LLPtrSkipMap(); - - // basic constructor including sorter - LLPtrSkipMap(insert_func insert_first, equals_func equals); - - ~LLPtrSkipMap(); - - void setInsertFirst(insert_func insert_first); - void setEquals(equals_func equals); - - DATA_T &addData(const INDEX_T &index, DATA_T datap); - DATA_T &addData(const INDEX_T &index); - DATA_T &getData(const INDEX_T &index); - DATA_T &operator[](const INDEX_T &index); - - // If index present, returns data. - // If index not present, adds <index,NULL> and returns NULL. - DATA_T &getData(const INDEX_T &index, BOOL &b_new_entry); - - // returns data entry before and after index - BOOL getInterval(const INDEX_T &index, INDEX_T &index_before, INDEX_T &index_after, - DATA_T &data_before, DATA_T &data_after ); - - // Returns TRUE if data present in map. - BOOL checkData(const INDEX_T &index); - - // Returns TRUE if key is present in map. This is useful if you - // are potentially storing NULL pointers in the map - BOOL checkKey(const INDEX_T &index); - - // If there, returns the data. - // If not, returns NULL. - // Never adds entries to the map. - DATA_T getIfThere(const INDEX_T &index); - - INDEX_T reverseLookup(const DATA_T datap); - - // returns number of items in the list - S32 getLength(); // WARNING! getLength is O(n), not O(1)! - - BOOL removeData(const INDEX_T &index); - BOOL deleteData(const INDEX_T &index); - - // remove all nodes from the list but do not delete data - void removeAllData(); - void deleteAllData(); - - // place mCurrentp on first node - void resetList(); - - // return the data currently pointed to - DATA_T getCurrentDataWithoutIncrement(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_T getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - DATA_T getNextData(); - - INDEX_T getNextKey(); - - // return the key currently pointed to - INDEX_T getCurrentKeyWithoutIncrement(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - void removeCurrentData(); - - void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_T getFirstData(); - - INDEX_T getFirstKey(); - - static BOOL defaultEquals(const INDEX_T &first, const INDEX_T &second) - { - return first == second; - } - -private: - // don't generate implicit copy constructor or copy assignment - LLPtrSkipMap(const LLPtrSkipMap &); - LLPtrSkipMap &operator=(const LLPtrSkipMap &); - -private: - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *mUpdate[BINARY_DEPTH]; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *mCurrentp; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const INDEX_T &first, const INDEX_T &second); - BOOL (*mEquals)(const INDEX_T &first, const INDEX_T &second); - S32 mNumberOfSteps; -}; - -////////////////////////////////////////////////// -// -// LLPtrSkipMap implementation -// -// - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap() - : mInsertFirst(NULL), - mEquals(defaultEquals), - mNumberOfSteps(0) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap(insert_func insert_first, - equals_func equals) -: mInsertFirst(insert_first), - mEquals(equals), - mNumberOfSteps(0) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::~LLPtrSkipMap() -{ - removeAllData(); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::setInsertFirst(insert_func insert_first) -{ - mInsertFirst = insert_first; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::setEquals(equals_func equals) -{ - mEquals = equals; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::addData(const INDEX_T &index, DATA_T datap) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // replace the existing data if a node is already there - if ( (current) - &&(mEquals(current->mIndex, index))) - { - current->mData = datap; - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - { - break; - } - } - - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *snode - = new LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>(index, datap); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::addData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *snode - = new LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - mNumberOfSteps++; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *snode - = new LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - - return snode->mData; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getInterval(const INDEX_T &index, - INDEX_T &index_before, - INDEX_T &index_after, - DATA_T &data_before, - DATA_T &data_after) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - BOOL both_found = TRUE; - - if (current != &mHead) - { - index_before = current->mIndex; - data_before = current->mData; - } - else - { - data_before = 0; - index_before = 0; - both_found = FALSE; - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - data_after = current->mData; - index_after = current->mIndex; - } - else - { - data_after = 0; - index_after = 0; - both_found = FALSE; - } - - return both_found; -} - - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::operator[](const INDEX_T &index) -{ - - return getData(index); -} - -// If index present, returns data. -// If index not present, adds <index,NULL> and returns NULL. -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getData(const INDEX_T &index, BOOL &b_new_entry) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - b_new_entry = TRUE; - addData(index); - - return current->mData; -} - -// Returns TRUE if data present in map. -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::checkData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - // Gets rid of some compiler ambiguity for the LLPointer<> templated class. - if (current->mData) - { - return mEquals(current->mIndex, index); - } - } - - return FALSE; -} - -// Returns TRUE if key is present in map. This is useful if you -// are potentially storing NULL pointers in the map -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::checkKey(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mIndex, index); - } - - return FALSE; -} - -// If there, returns the data. -// If not, returns NULL. -// Never adds entries to the map. -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getIfThere(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - if (mEquals(current->mIndex, index)) - { - return current->mData; - } - } - - // Avoid Linux compiler warning on returning NULL. - return (DATA_T)0; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::reverseLookup(const DATA_T datap) -{ - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - - while (current) - { - if (datap == current->mData) - { - - return current->mIndex; - } - current = *current->mForward; - } - - // not found! return NULL - return INDEX_T(); -} - -// returns number of items in the list -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline S32 LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getLength() -{ - U32 length = 0; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>* temp; - for (temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - - return length; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::removeData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - // clean up cuurent - current->removeData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::deleteData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - // clean up cuurent - current->deleteData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - -// remove all nodes from the list but do not delete data -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::removeAllData() -{ - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::deleteAllData() -{ - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// return the data currently pointed to -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getCurrentDataWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes warning - return (DATA_T)0; // equivalent, but no warning - } -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes warning - return (DATA_T)0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_T)0; // equivalent, but removes warning - } -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getNextKey() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -// return the key currently pointed to -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getCurrentKeyWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mIndex; - } - else - { - //return NULL; // causes compile warning - return (INDEX_T)0; // equivalent, but removes warning - } -} - - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mIndex); - } -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mIndex); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_T)0; // equivalent, but removes warning - } -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getFirstKey() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -#endif diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index abf47a0f57..4339f203db 100755 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -28,6 +28,7 @@ #include "llstl.h" #include "lltimer.h" // ms_sleep() +#include "lltracethreadrecorder.h" //============================================================================ @@ -134,8 +135,8 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms) pending = getPending(); if(pending > 0) { - unpause(); - } + unpause(); + } } else { @@ -403,6 +404,7 @@ S32 LLQueuedThread::processNextRequest() QueuedRequest *req; // Get next request from pool lockData(); + while(1) { req = NULL; @@ -467,10 +469,11 @@ S32 LLQueuedThread::processNextRequest() ms_sleep(1); // sleep the thread a little } } + + LLTrace::get_thread_recorder()->pushToMaster(); } S32 pending = getPending(); - return pending; } @@ -499,6 +502,7 @@ void LLQueuedThread::run() if (isQuitting()) { + LLTrace::get_thread_recorder()->pushToMaster(); endThread(); break; } @@ -507,8 +511,9 @@ void LLQueuedThread::run() threadedUpdate(); - int res = processNextRequest(); - if (res == 0) + int pending_work = processNextRequest(); + + if (pending_work == 0) { mIdleThread = TRUE; ms_sleep(1); diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index bb0d60247e..c8ec0a0bc0 100755 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -29,7 +29,6 @@ #include <list> -#include <boost/type_traits.hpp> #include "llsingleton.h" #include "llstl.h" @@ -47,12 +46,11 @@ template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultC class LLRegistry { public: - typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; - typedef typename boost::add_reference<typename boost::add_const<KEY>::type>::type ref_const_key_t; - typedef typename boost::add_reference<typename boost::add_const<VALUE>::type>::type ref_const_value_t; - typedef typename boost::add_reference<VALUE>::type ref_value_t; - typedef typename boost::add_pointer<typename boost::add_const<VALUE>::type>::type ptr_const_value_t; - typedef typename boost::add_pointer<VALUE>::type ptr_value_t; + typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; + typedef const KEY& ref_const_key_t; + typedef const VALUE& ref_const_value_t; + typedef const VALUE* ptr_const_value_t; + typedef VALUE* ptr_value_t; class Registrar { diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 9f4460a988..50815b2cc6 100755 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -102,13 +102,13 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool //readSDValues(sd, block); } -void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) +void LLParamSDParser::writeSDImpl(LLSD& sd, const LLInitParam::BaseBlock& block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block) { mNameStack.clear(); mWriteRootSD = &sd; name_stack_t name_stack; - block.serializeBlock(*this, name_stack); + block.serializeBlock(*this, name_stack, rules, diff_block); } /*virtual*/ std::string LLParamSDParser::getCurrentElementName() @@ -299,6 +299,7 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); readSDValues(cb, sd, stack); } + namespace LLInitParam { // LLSD specialization @@ -329,13 +330,14 @@ namespace LLInitParam p.writeValue<LLSD::String>(sd.asString(), name_stack); } - void ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const + bool ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const { // attempt to write LLSD out directly - if (!p.writeValue<LLSD>(mValue, name_stack)) + if (!p.writeValue<LLSD>(mValue, name_stack_range)) { // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) - LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack); + LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack_range); } + return true; } } diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h index 6ef5debd7b..7cfc265c62 100755 --- a/indra/llcommon/llsdparam.h +++ b/indra/llcommon/llsdparam.h @@ -30,6 +30,7 @@ #include "llinitparam.h" #include "boost/function.hpp" +#include "llfasttimer.h" struct LL_COMMON_API LLParamSDParserUtilities { @@ -50,11 +51,28 @@ typedef LLInitParam::Parser parser_t; public: LLParamSDParser(); void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); - void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); + template<typename BLOCK> + void writeSD(LLSD& sd, + const BLOCK& block, + const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), + const LLInitParam::BaseBlock* diff_block = NULL) + { + if (!diff_block + && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) + { + diff_block = &LLInitParam::defaultValue<BLOCK>(); + } + writeSDImpl(sd, block, rules, diff_block); + } /*virtual*/ std::string getCurrentElementName(); private: + void writeSDImpl(LLSD& sd, + const LLInitParam::BaseBlock& block, + const LLInitParam::predicate_rule_t, + const LLInitParam::BaseBlock* diff_block); + void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); template<typename T> diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index eb8e2c9456..9b49e52377 100755 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -28,5 +28,4 @@ #include "llsingleton.h" -std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL; diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 49d99f2cd0..b9cb8e3d41 100755 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -30,38 +30,6 @@ #include <typeinfo> #include <boost/noncopyable.hpp> -/// @brief A global registry of all singletons to prevent duplicate allocations -/// across shared library boundaries -class LL_COMMON_API LLSingletonRegistry { - private: - typedef std::map<std::string, void *> TypeMap; - static TypeMap * sSingletonMap; - - static void checkInit() - { - if(sSingletonMap == NULL) - { - sSingletonMap = new TypeMap(); - } - } - - public: - template<typename T> static void * & get() - { - std::string name(typeid(T).name()); - - checkInit(); - - // the first entry of the pair returned by insert will be either the existing - // iterator matching our key, or the newly inserted NULL initialized entry - // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html - TypeMap::iterator result = - sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first; - - return result->second; - } -}; - // LLSingleton implements the getInstance() method part of the Singleton // pattern. It can't make the derived class constructors protected, though, so // you have to do that yourself. @@ -99,22 +67,30 @@ private: INITIALIZED, DELETED } EInitState; + + static DERIVED_TYPE* constructSingleton() + { + return new DERIVED_TYPE(); + } // stores pointer to singleton instance - // and tracks initialization state of singleton - struct SingletonInstanceData + struct SingletonLifetimeManager { - EInitState mInitState; - DERIVED_TYPE* mSingletonInstance; - - SingletonInstanceData() - : mSingletonInstance(NULL), - mInitState(UNINITIALIZED) - {} - - ~SingletonInstanceData() + SingletonLifetimeManager() + { + construct(); + } + + static void construct() { - if (mInitState != DELETED) + sData.mInitState = CONSTRUCTING; + sData.mInstance = constructSingleton(); + sData.mInitState = INITIALIZING; + } + + ~SingletonLifetimeManager() + { + if (sData.mInitState != DELETED) { deleteSingleton(); } @@ -124,9 +100,8 @@ private: public: virtual ~LLSingleton() { - SingletonInstanceData& data = getData(); - data.mSingletonInstance = NULL; - data.mInitState = DELETED; + sData.mInstance = NULL; + sData.mInitState = DELETED; } /** @@ -151,50 +126,49 @@ public: */ static void deleteSingleton() { - delete getData().mSingletonInstance; - getData().mSingletonInstance = NULL; - getData().mInitState = DELETED; + delete sData.mInstance; + sData.mInstance = NULL; + sData.mInitState = DELETED; } - static SingletonInstanceData& getData() - { - // this is static to cache the lookup results - static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>(); - - // *TODO - look into making this threadsafe - if(NULL == registry) - { - static SingletonInstanceData data; - registry = &data; - } - - return *static_cast<SingletonInstanceData *>(registry); - } static DERIVED_TYPE* getInstance() { - SingletonInstanceData& data = getData(); + static SingletonLifetimeManager sLifeTimeMgr; - if (data.mInitState == CONSTRUCTING) + switch (sData.mInitState) { + case UNINITIALIZED: + // should never be uninitialized at this point + llassert(false); + return NULL; + case CONSTRUCTING: llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; - } - - if (data.mInitState == DELETED) - { + return NULL; + case INITIALIZING: + // go ahead and flag ourselves as initialized so we can be reentrant during initialization + sData.mInitState = INITIALIZED; + // initialize singleton after constructing it so that it can reference other singletons which in turn depend on it, + // thus breaking cyclic dependencies + sData.mInstance->initSingleton(); + return sData.mInstance; + case INITIALIZED: + return sData.mInstance; + case DELETED: llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; + SingletonLifetimeManager::construct(); + // same as first time construction + sData.mInitState = INITIALIZED; + sData.mInstance->initSingleton(); + return sData.mInstance; } - - if (!data.mSingletonInstance) - { - data.mInitState = CONSTRUCTING; - data.mSingletonInstance = new DERIVED_TYPE(); - data.mInitState = INITIALIZING; - data.mSingletonInstance->initSingleton(); - data.mInitState = INITIALIZED; - } - - return data.mSingletonInstance; + + return NULL; + } + + static DERIVED_TYPE* getIfExists() + { + return sData.mInstance; } // Reference version of getInstance() @@ -208,18 +182,31 @@ public: // Use this to avoid accessing singletons before the can safely be constructed static bool instanceExists() { - return getData().mInitState == INITIALIZED; + return sData.mInitState == INITIALIZED; } // Has this singleton already been deleted? // Use this to avoid accessing singletons from a static object's destructor static bool destroyed() { - return getData().mInitState == DELETED; + return sData.mInitState == DELETED; } private: + virtual void initSingleton() {} + + struct SingletonData + { + // explicitly has a default constructor so that member variables are zero initialized in BSS + // and only changed by singleton logic, not constructor running during startup + EInitState mInitState; + DERIVED_TYPE* mInstance; + }; + static SingletonData sData; }; +template<typename T> +typename LLSingleton<T>::SingletonData LLSingleton<T>::sData; + #endif diff --git a/indra/llcommon/llskiplist.h b/indra/llcommon/llskiplist.h deleted file mode 100755 index ed132381f9..0000000000 --- a/indra/llcommon/llskiplist.h +++ /dev/null @@ -1,517 +0,0 @@ -/** - * @file llskiplist.h - * @brief skip list implementation - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLSKIPLIST_H -#define LL_LLSKIPLIST_H - -#include "llrand.h" -#include "llrand.h" - -// NOTA BENE: Insert first needs to be < NOT <= -// Binary depth must be >= 2 -template <class DATA_TYPE, S32 BINARY_DEPTH = 10> -class LLSkipList -{ -public: - typedef BOOL (*compare)(const DATA_TYPE& first, const DATA_TYPE& second); - typedef compare insert_func; - typedef compare equals_func; - - void init(); - - // basic constructor - LLSkipList(); - - // basic constructor including sorter - LLSkipList(insert_func insert_first, equals_func equals); - ~LLSkipList(); - - inline void setInsertFirst(insert_func insert_first); - inline void setEquals(equals_func equals); - - inline BOOL addData(const DATA_TYPE& data); - inline BOOL checkData(const DATA_TYPE& data); - - // returns number of items in the list - inline S32 getLength() const; // NOT a constant time operation, traverses entire list! - - inline BOOL moveData(const DATA_TYPE& data, LLSkipList *newlist); - - inline BOOL removeData(const DATA_TYPE& data); - - // remove all nodes from the list but do not delete data - inline void removeAllNodes(); - - // place mCurrentp on first node - inline void resetList(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - inline DATA_TYPE getNextData(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void removeCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE getFirstData(); - - class LLSkipNode - { - public: - LLSkipNode() - : mData(0) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - LLSkipNode(DATA_TYPE data) - : mData(data) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - ~LLSkipNode() - { - } - - DATA_TYPE mData; - LLSkipNode *mForward[BINARY_DEPTH]; - - private: - // Disallow copying of LLSkipNodes by not implementing these methods. - LLSkipNode(const LLSkipNode &); - LLSkipNode &operator=(const LLSkipNode &); - }; - - static BOOL defaultEquals(const DATA_TYPE& first, const DATA_TYPE& second) - { - return first == second; - } - -private: - LLSkipNode mHead; - LLSkipNode *mUpdate[BINARY_DEPTH]; - LLSkipNode *mCurrentp; - LLSkipNode *mCurrentOperatingp; - S32 mLevel; - insert_func mInsertFirst; - equals_func mEquals; - -private: - // Disallow copying of LLSkipNodes by not implementing these methods. - LLSkipList(const LLSkipList &); - LLSkipList &operator=(const LLSkipList &); -}; - - -/////////////////////// -// -// Implementation -// - - -// Binary depth must be >= 2 -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::init() -{ - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// basic constructor -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList() -: mInsertFirst(NULL), - mEquals(defaultEquals) -{ - init(); -} - -// basic constructor including sorter -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList(insert_func insert, - equals_func equals) -: mInsertFirst(insert), - mEquals(equals) -{ - init(); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::~LLSkipList() -{ - removeAllNodes(); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(insert_func insert_first) -{ - mInsertFirst = insert_first; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(equals_func equals) -{ - mEquals = equals; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::addData(const DATA_TYPE& data) -{ - S32 level; - LLSkipNode *current = &mHead; - LLSkipNode *temp; - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLSkipNode *snode = new LLSkipNode(data); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return TRUE; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE& data) -{ - S32 level; - LLSkipNode *current = &mHead; - LLSkipNode *temp; - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - - if (current) - { - return mEquals(current->mData, data); - } - - return FALSE; -} - -// returns number of items in the list -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline S32 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() const -{ - U32 length = 0; - for (LLSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - return length; -} - - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE& data, LLSkipList *newlist) -{ - BOOL removed = removeData(data); - BOOL added = newlist->addData(data); - return removed && added; -} - - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE& data) -{ - S32 level; - LLSkipNode *current = &mHead; - LLSkipNode *temp; - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = current->mForward[0]; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = current->mForward[0]; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// remove all nodes from the list but do not delete data -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes() -{ - LLSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_TYPE)0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_TYPE)0; // equivalent, but no warning - } -} - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mData); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_TYPE)0; // equivalent, but no warning - } -} - - -#endif diff --git a/indra/llcommon/llskipmap.h b/indra/llcommon/llskipmap.h deleted file mode 100755 index 49ff2928d1..0000000000 --- a/indra/llcommon/llskipmap.h +++ /dev/null @@ -1,1022 +0,0 @@ -/** - * @file llskipmap.h - * @brief Associative container based on the skiplist algorithm. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSKIPMAP_H -#define LL_LLSKIPMAP_H - -#include "llerror.h" - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH = 8> -class LLSkipMap -{ -public: - // basic constructor - LLSkipMap(); - - // basic constructor including sorter - LLSkipMap(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second), - BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)); - - ~LLSkipMap(); - - void setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second)); - void setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)); - - DATA_TYPE &addData(const INDEX_TYPE &index, DATA_TYPE datap); - DATA_TYPE &addData(const INDEX_TYPE &index); - DATA_TYPE &getData(const INDEX_TYPE &index); - DATA_TYPE &operator[](const INDEX_TYPE &index); - - // If index present, returns data. - // If index not present, adds <index,NULL> and returns NULL. - DATA_TYPE &getData(const INDEX_TYPE &index, BOOL &b_new_entry); - - // Returns TRUE if data present in map. - BOOL checkData(const INDEX_TYPE &index); - - // Returns TRUE if key is present in map. This is useful if you - // are potentially storing NULL pointers in the map - BOOL checkKey(const INDEX_TYPE &index); - - // If there, returns the data. - // If not, returns NULL. - // Never adds entries to the map. - DATA_TYPE getIfThere(const INDEX_TYPE &index); - - INDEX_TYPE reverseLookup(const DATA_TYPE datap); - - // returns number of items in the list - S32 getLength(); // WARNING! getLength is O(n), not O(1)! - - BOOL removeData(const INDEX_TYPE &index); - - // remove all nodes from the list but do not delete data - void removeAllData(); - - // place mCurrentp on first node - void resetList(); - - // return the data currently pointed to - DATA_TYPE getCurrentDataWithoutIncrement(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_TYPE getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - DATA_TYPE getNextData(); - - INDEX_TYPE getNextKey(); - - // return the key currently pointed to - INDEX_TYPE getCurrentKeyWithoutIncrement(); - - // The internal iterator is at the end of the list. - BOOL notDone() const; - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - void removeCurrentData(); - - void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_TYPE getFirstData(); - - INDEX_TYPE getFirstKey(); - - class LLSkipMapNode - { - public: - LLSkipMapNode() - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mIndex; - - for (i = 0; i < (S32)sizeof(INDEX_TYPE); i++) - { - *(zero + i) = 0; - } - - zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_TYPE); i++) - { - *(zero + i) = 0; - } - } - - LLSkipMapNode(const INDEX_TYPE &index) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_TYPE); i++) - { - *(zero + i) = 0; - } - } - - LLSkipMapNode(const INDEX_TYPE &index, DATA_TYPE datap) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - mData = datap; - } - - ~LLSkipMapNode() - { - } - - - INDEX_TYPE mIndex; - DATA_TYPE mData; - LLSkipMapNode *mForward[BINARY_DEPTH]; - - private: - // Disallow copying of LLSkipMapNodes by not implementing these methods. - LLSkipMapNode(const LLSkipMapNode &); - LLSkipMapNode &operator=(const LLSkipMapNode &rhs); - }; - - static BOOL defaultEquals(const INDEX_TYPE &first, const INDEX_TYPE &second) - { - return first == second; - } - -private: - // don't generate implicit copy constructor or copy assignment - LLSkipMap(const LLSkipMap &); - LLSkipMap &operator=(const LLSkipMap &); - -private: - LLSkipMapNode mHead; - LLSkipMapNode *mUpdate[BINARY_DEPTH]; - LLSkipMapNode *mCurrentp; - LLSkipMapNode *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const INDEX_TYPE &first, const INDEX_TYPE &second); - BOOL (*mEquals)(const INDEX_TYPE &first, const INDEX_TYPE &second); - S32 mNumberOfSteps; -}; - -////////////////////////////////////////////////// -// -// LLSkipMap implementation -// - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap() - : mInsertFirst(NULL), - mEquals(defaultEquals) -{ - // Skipmaps must have binary depth of at least 2 - cassert(BINARY_DEPTH >= 2); - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second), - BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)) - : mInsertFirst(insert_first), - mEquals(equals) -{ - // Skipmaps must have binary depth of at least 2 - cassert(BINARY_DEPTH >= 2); - - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::~LLSkipMap() -{ - removeAllData(); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second)) -{ - mInsertFirst = insert_first; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)) -{ - mEquals = equals; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index, DATA_TYPE datap) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // replace the existing data if a node is already there - if ( (current) - &&(mEquals(current->mIndex, index))) - { - current->mData = datap; - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (rand() & 1) - { - break; - } - } - - LLSkipMapNode *snode = new LLSkipMapNode(index, datap); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (rand() & 1) - break; - } - - LLSkipMapNode *snode = new LLSkipMapNode(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - mNumberOfSteps++; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (rand() & 1) - break; - } - - LLSkipMapNode *snode = new LLSkipMapNode(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - - return snode->mData; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::operator[](const INDEX_TYPE &index) -{ - - return getData(index); -} - -// If index present, returns data. -// If index not present, adds <index,NULL> and returns NULL. -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index, BOOL &b_new_entry) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - b_new_entry = TRUE; - addData(index); - - return current->mData; -} - -// Returns TRUE if data present in map. -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - // Gets rid of some compiler ambiguity for the LLPointer<> templated class. - if (current->mData) - { - return mEquals(current->mIndex, index); - } - } - - return FALSE; -} - -// Returns TRUE if key is present in map. This is useful if you -// are potentially storing NULL pointers in the map -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkKey(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mIndex, index); - } - - return FALSE; -} - -// If there, returns the data. -// If not, returns NULL. -// Never adds entries to the map. -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getIfThere(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - if (mEquals(current->mIndex, index)) - { - return current->mData; - } - } - - // Avoid Linux compiler warning on returning NULL. - return DATA_TYPE(); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::reverseLookup(const DATA_TYPE datap) -{ - LLSkipMapNode *current = &mHead; - - while (current) - { - if (datap == current->mData) - { - - return current->mIndex; - } - current = *current->mForward; - } - - // not found! return NULL - return INDEX_TYPE(); -} - -// returns number of items in the list -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline S32 LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getLength() -{ - U32 length = 0; - for (LLSkipMapNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - - return length; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - - -// remove all nodes from the list but do not delete data -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeAllData() -{ - LLSkipMapNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// place mCurrentp on first node -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// return the data currently pointed to -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentDataWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mData; - } - else - { - return DATA_TYPE(); - } -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - // Basic types, like int, have default constructors that initialize - // them to zero. g++ 2.95 supports this. "int()" is zero. - // This also is nice for LLUUID() - return DATA_TYPE(); - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - // Basic types, like int, have default constructors that initialize - // them to zero. g++ 2.95 supports this. "int()" is zero. - // This also is nice for LLUUID() - return DATA_TYPE(); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextKey() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -// return the key currently pointed to -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentKeyWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mIndex; - } - else - { - // See comment for getNextData() - return INDEX_TYPE(); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::notDone() const -{ - if (mCurrentOperatingp) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mIndex); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mIndex); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - // See comment for getNextData() - return DATA_TYPE(); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstKey() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -#endif diff --git a/indra/llcommon/llsortedvector.h b/indra/llcommon/llsortedvector.h deleted file mode 100755 index 391b82ee44..0000000000 --- a/indra/llcommon/llsortedvector.h +++ /dev/null @@ -1,152 +0,0 @@ -/** - * @file llsortedvector.h - * @author Nat Goodspeed - * @date 2012-04-08 - * @brief LLSortedVector class wraps a vector that we maintain in sorted - * order so we can perform binary-search lookups. - * - * $LicenseInfo:firstyear=2012&license=viewerlgpl$ - * Copyright (c) 2012, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLSORTEDVECTOR_H) -#define LL_LLSORTEDVECTOR_H - -#include <vector> -#include <algorithm> - -/** - * LLSortedVector contains a std::vector<std::pair> that we keep sorted on the - * first of the pair. This makes insertion somewhat more expensive than simple - * std::vector::push_back(), but allows us to use binary search for lookups. - * It's intended for small aggregates where lookup is far more performance- - * critical than insertion; in such cases a binary search on a small, sorted - * std::vector can be more performant than a std::map lookup. - */ -template <typename KEY, typename VALUE> -class LLSortedVector -{ -public: - typedef LLSortedVector<KEY, VALUE> self; - typedef KEY key_type; - typedef VALUE mapped_type; - typedef std::pair<key_type, mapped_type> value_type; - typedef std::vector<value_type> PairVector; - typedef typename PairVector::iterator iterator; - typedef typename PairVector::const_iterator const_iterator; - - /// Empty - LLSortedVector() {} - - /// Fixed initial size - LLSortedVector(std::size_t size): - mVector(size) - {} - - /// Bulk load - template <typename ITER> - LLSortedVector(ITER begin, ITER end): - mVector(begin, end) - { - // Allow caller to dump in a bunch of (pairs convertible to) - // value_type if desired, but make sure we sort afterwards. - std::sort(mVector.begin(), mVector.end()); - } - - /// insert(key, value) - std::pair<iterator, bool> insert(const key_type& key, const mapped_type& value) - { - return insert(value_type(key, value)); - } - - /// insert(value_type) - std::pair<iterator, bool> insert(const value_type& pair) - { - typedef std::pair<iterator, bool> iterbool; - iterator found = std::lower_bound(mVector.begin(), mVector.end(), pair, - less<value_type>()); - // have to check for end() before it's even valid to dereference - if (found == mVector.end()) - { - std::size_t index(mVector.size()); - mVector.push_back(pair); - // don't forget that push_back() invalidates 'found' - return iterbool(mVector.begin() + index, true); - } - if (found->first == pair.first) - { - return iterbool(found, false); - } - // remember that insert() invalidates 'found' -- save index - std::size_t index(found - mVector.begin()); - mVector.insert(found, pair); - // okay, convert from index back to iterator - return iterbool(mVector.begin() + index, true); - } - - iterator begin() { return mVector.begin(); } - iterator end() { return mVector.end(); } - const_iterator begin() const { return mVector.begin(); } - const_iterator end() const { return mVector.end(); } - - bool empty() const { return mVector.empty(); } - std::size_t size() const { return mVector.size(); } - - /// find - iterator find(const key_type& key) - { - iterator found = std::lower_bound(mVector.begin(), mVector.end(), - value_type(key, mapped_type()), - less<value_type>()); - if (found == mVector.end() || found->first != key) - return mVector.end(); - return found; - } - - const_iterator find(const key_type& key) const - { - return const_cast<self*>(this)->find(key); - } - -private: - // Define our own 'less' comparator so we can specialize without messing - // with std::less. - template <typename T> - struct less: public std::less<T> {}; - - // Specialize 'less' for an LLSortedVector::value_type involving - // std::type_info*. This is one of LLSortedVector's foremost use cases. We - // specialize 'less' rather than just defining a specific comparator - // because LLSortedVector should be usable for other key_types as well. - template <typename T> - struct less< std::pair<std::type_info*, T> >: - public std::binary_function<std::pair<std::type_info*, T>, - std::pair<std::type_info*, T>, - bool> - { - bool operator()(const std::pair<std::type_info*, T>& lhs, - const std::pair<std::type_info*, T>& rhs) const - { - return lhs.first->before(*rhs.first); - } - }; - - // Same as above, but with const std::type_info*. - template <typename T> - struct less< std::pair<const std::type_info*, T> >: - public std::binary_function<std::pair<const std::type_info*, T>, - std::pair<const std::type_info*, T>, - bool> - { - bool operator()(const std::pair<const std::type_info*, T>& lhs, - const std::pair<const std::type_info*, T>& rhs) const - { - return lhs.first->before(*rhs.first); - } - }; - - PairVector mVector; -}; - -#endif /* ! defined(LL_LLSORTEDVECTOR_H) */ diff --git a/indra/llcommon/llstack.h b/indra/llcommon/llstack.h deleted file mode 100755 index 315de6ba2d..0000000000 --- a/indra/llcommon/llstack.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file llstack.h - * @brief LLStack template class - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSTACK_H -#define LL_LLSTACK_H - -#include "linked_lists.h" - -template <class DATA_TYPE> class LLStack -{ -private: - LLLinkedList<DATA_TYPE> mStack; - -public: - LLStack() {} - ~LLStack() {} - - void push(DATA_TYPE *data) { mStack.addData(data); } - DATA_TYPE *pop() { DATA_TYPE *tempp = mStack.getFirstData(); mStack.removeCurrentData(); return tempp; } - void deleteAllData() { mStack.deleteAllData(); } - void removeAllNodes() { mStack.removeAllNodes(); } -}; - -#endif - diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index ccd7ef91c2..e0e9056380 100755 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -32,7 +32,7 @@ #include <iostream> #include <sstream> -#include "windows.h" +#include "llwin32headerslean.h" #include "Dbghelp.h" typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp deleted file mode 100755 index 3678c8e1c1..0000000000 --- a/indra/llcommon/llstat.cpp +++ /dev/null @@ -1,404 +0,0 @@ -/** - * @file llstat.cpp - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstat.h" -#include "lllivefile.h" -#include "llerrorcontrol.h" -#include "llframetimer.h" -#include "timing.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "llstl.h" -#include "u64.h" - - -// statics -//------------------------------------------------------------------------ -LLTimer LLStat::sTimer; -LLFrameTimer LLStat::sFrameTimer; - -void LLStat::reset() -{ - mNumValues = 0; - mLastValue = 0.f; - delete[] mBins; - mBins = new ValueEntry[mNumBins]; - mCurBin = mNumBins-1; - mNextBin = 0; -} - -LLStat::LLStat(std::string name, S32 num_bins, BOOL use_frame_timer) -: mUseFrameTimer(use_frame_timer), - mNumBins(num_bins), - mName(name), - mBins(NULL) -{ - llassert(mNumBins > 0); - mLastTime = 0.f; - - reset(); - - if (!mName.empty()) - { - stat_map_t::iterator iter = getStatList().find(mName); - if (iter != getStatList().end()) - llwarns << "LLStat with duplicate name: " << mName << llendl; - getStatList().insert(std::make_pair(mName, this)); - } -} - -LLStat::stat_map_t& LLStat::getStatList() -{ - static LLStat::stat_map_t stat_list; - return stat_list; -} - - -LLStat::~LLStat() -{ - delete[] mBins; - - if (!mName.empty()) - { - // handle multiple entries with the same name - stat_map_t::iterator iter = getStatList().find(mName); - while (iter != getStatList().end() && iter->second != this) - ++iter; - getStatList().erase(iter); - } -} - -void LLStat::start() -{ - if (mUseFrameTimer) - { - mBins[mNextBin].mBeginTime = sFrameTimer.getElapsedSeconds(); - } - else - { - mBins[mNextBin].mBeginTime = sTimer.getElapsedTimeF64(); - } -} - -void LLStat::addValue(const F32 value) -{ - if (mNumValues < mNumBins) - { - mNumValues++; - } - - // Increment the bin counters. - mCurBin++; - if (mCurBin >= mNumBins) - { - mCurBin = 0; - } - mNextBin++; - if (mNextBin >= mNumBins) - { - mNextBin = 0; - } - - mBins[mCurBin].mValue = value; - if (mUseFrameTimer) - { - mBins[mCurBin].mTime = sFrameTimer.getElapsedSeconds(); - } - else - { - mBins[mCurBin].mTime = sTimer.getElapsedTimeF64(); - } - mBins[mCurBin].mDT = (F32)(mBins[mCurBin].mTime - mBins[mCurBin].mBeginTime); - - //this value is used to prime the min/max calls - mLastTime = mBins[mCurBin].mTime; - mLastValue = value; - - // Set the begin time for the next stat segment. - mBins[mNextBin].mBeginTime = mBins[mCurBin].mTime; - mBins[mNextBin].mTime = mBins[mCurBin].mTime; - mBins[mNextBin].mDT = 0.f; -} - - -F32 LLStat::getMax() const -{ - S32 i; - F32 current_max = mLastValue; - if (mNumBins == 0) - { - current_max = 0.f; - } - else - { - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - if (mBins[i].mValue > current_max) - { - current_max = mBins[i].mValue; - } - } - } - return current_max; -} - -F32 LLStat::getMean() const -{ - S32 i; - F32 current_mean = 0.f; - S32 samples = 0; - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - current_mean += mBins[i].mValue; - samples++; - } - - // There will be a wrap error at 2^32. :) - if (samples != 0) - { - current_mean /= samples; - } - else - { - current_mean = 0.f; - } - return current_mean; -} - -F32 LLStat::getMin() const -{ - S32 i; - F32 current_min = mLastValue; - - if (mNumBins == 0) - { - current_min = 0.f; - } - else - { - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - if (mBins[i].mValue < current_min) - { - current_min = mBins[i].mValue; - } - } - } - return current_min; -} - -F32 LLStat::getPrev(S32 age) const -{ - S32 bin; - bin = mCurBin - age; - - while (bin < 0) - { - bin += mNumBins; - } - - if (bin == mNextBin) - { - // Bogus for bin we're currently working on. - return 0.f; - } - return mBins[bin].mValue; -} - -F32 LLStat::getPrevPerSec(S32 age) const -{ - S32 bin; - bin = mCurBin - age; - - while (bin < 0) - { - bin += mNumBins; - } - - if (bin == mNextBin) - { - // Bogus for bin we're currently working on. - return 0.f; - } - return mBins[bin].mValue / mBins[bin].mDT; -} - -F32 LLStat::getCurrent() const -{ - return mBins[mCurBin].mValue; -} - -F32 LLStat::getCurrentPerSec() const -{ - return mBins[mCurBin].mValue / mBins[mCurBin].mDT; -} - -F32 LLStat::getMeanPerSec() const -{ - S32 i; - F32 value = 0.f; - F32 dt = 0.f; - - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - value += mBins[i].mValue; - dt += mBins[i].mDT; - } - - if (dt > 0.f) - { - return value/dt; - } - else - { - return 0.f; - } -} - -F32 LLStat::getMeanDuration() const -{ - F32 dur = 0.0f; - S32 count = 0; - for (S32 i=0; (i < mNumBins) && (i < mNumValues); i++) - { - if (i == mNextBin) - { - continue; - } - dur += mBins[i].mDT; - count++; - } - - if (count > 0) - { - dur /= F32(count); - return dur; - } - else - { - return 0.f; - } -} - -F32 LLStat::getMaxPerSec() const -{ - F32 value; - - if (mNextBin != 0) - { - value = mBins[0].mValue/mBins[0].mDT; - } - else if (mNumValues > 0) - { - value = mBins[1].mValue/mBins[1].mDT; - } - else - { - value = 0.f; - } - - for (S32 i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - value = llmax(value, mBins[i].mValue/mBins[i].mDT); - } - return value; -} - -F32 LLStat::getMinPerSec() const -{ - S32 i; - F32 value; - - if (mNextBin != 0) - { - value = mBins[0].mValue/mBins[0].mDT; - } - else if (mNumValues > 0) - { - value = mBins[1].mValue/mBins[0].mDT; - } - else - { - value = 0.f; - } - - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - value = llmin(value, mBins[i].mValue/mBins[i].mDT); - } - return value; -} - -U32 LLStat::getNumValues() const -{ - return mNumValues; -} - -S32 LLStat::getNumBins() const -{ - return mNumBins; -} - -S32 LLStat::getNextBin() const -{ - return mNextBin; -} - -F64 LLStat::getLastTime() const -{ - return mLastTime; -} diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h deleted file mode 100755 index 38377a010b..0000000000 --- a/indra/llcommon/llstat.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file llstat.h - * @brief Runtime statistics accumulation. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSTAT_H -#define LL_LLSTAT_H - -#include <map> - -#include "lltimer.h" -#include "llframetimer.h" - -class LLSD; - -// ---------------------------------------------------------------------------- -class LL_COMMON_API LLStat -{ -private: - typedef std::multimap<std::string, LLStat*> stat_map_t; - - static stat_map_t& getStatList(); - -public: - LLStat(std::string name = std::string(), S32 num_bins = 32, BOOL use_frame_timer = FALSE); - ~LLStat(); - - void start(); // Start the timer for the current "frame", otherwise uses the time tracked from - // the last addValue - void reset(); - void addValue(const F32 value = 1.f); // Adds the current value being tracked, and tracks the DT. - void addValue(const S32 value) { addValue((F32)value); } - void addValue(const U32 value) { addValue((F32)value); } - - S32 getNextBin() const; - - F32 getPrev(S32 age) const; // Age is how many "addValues" previously - zero is current - F32 getPrevPerSec(S32 age) const; // Age is how many "addValues" previously - zero is current - F32 getCurrent() const; - F32 getCurrentPerSec() const; - - F32 getMin() const; - F32 getMinPerSec() const; - F32 getMean() const; - F32 getMeanPerSec() const; - F32 getMeanDuration() const; - F32 getMax() const; - F32 getMaxPerSec() const; - - U32 getNumValues() const; - S32 getNumBins() const; - - F64 getLastTime() const; -private: - BOOL mUseFrameTimer; - U32 mNumValues; - U32 mNumBins; - F32 mLastValue; - F64 mLastTime; - - struct ValueEntry - { - ValueEntry() - : mValue(0.f), - mBeginTime(0.0), - mTime(0.0), - mDT(0.f) - {} - F32 mValue; - F64 mBeginTime; - F64 mTime; - F32 mDT; - }; - ValueEntry* mBins; - S32 mCurBin; - S32 mNextBin; - - std::string mName; - - static LLTimer sTimer; - static LLFrameTimer sFrameTimer; - -public: - static LLStat* getStat(const std::string& name) - { - // return the first stat that matches 'name' - stat_map_t::iterator iter = getStatList().find(name); - if (iter != getStatList().end()) - return iter->second; - else - return NULL; - } -}; - -#endif // LL_STAT_ diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index 81c4085d16..ab9b6709e8 100755 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -26,7 +26,7 @@ #ifndef LL_LLSTATENUMS_H #define LL_LLSTATENUMS_H -enum +enum ESimStatID { LL_SIM_STAT_TIME_DILATION = 0, LL_SIM_STAT_FPS = 1, diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index d3941e1bc9..424138dad1 100755 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -31,6 +31,7 @@ #include <algorithm> #include <map> #include <vector> +#include <list> #include <set> #include <deque> #include <typeinfo> diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 22c8681983..66c416bfdd 100755 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -28,11 +28,10 @@ #include "llstring.h" #include "llerror.h" +#include "llfasttimer.h" #if LL_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include <winsock2.h> -#include <windows.h> +#include "llwin32headerslean.h" #include <winnls.h> // for WideCharToMultiByte #endif diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index f9702868c8..17893c1910 100755 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -31,8 +31,9 @@ #include <cstdio> #include <locale> #include <iomanip> +#include <algorithm> #include "llsd.h" -#include "llfasttimer.h" +#include "llformat.h" #if LL_LINUX || LL_SOLARIS #include <wctype.h> diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 57a6de9060..95bbcbc816 100755 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -42,6 +42,7 @@ #include "llprocessor.h" #include "llerrorcontrol.h" #include "llevents.h" +#include "llformat.h" #include "lltimer.h" #include "llsdserialize.h" #include "llsdutil.h" @@ -58,9 +59,7 @@ using namespace llsd; #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> +# include "llwin32headerslean.h" # include <psapi.h> // GetPerformanceInfo() et al. #elif LL_DARWIN # include <errno.h> diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 1d56a52c32..118568d5ef 100755 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -29,8 +29,11 @@ #include "apr_portable.h" #include "llthread.h" +#include "llmutex.h" #include "lltimer.h" +#include "lltrace.h" +#include "lltracethreadrecorder.h" #if LL_LINUX || LL_SOLARIS #include <sched.h> @@ -56,12 +59,17 @@ // //---------------------------------------------------------------------------- -#if !LL_DARWIN -U32 ll_thread_local sThreadID = 0; +#if LL_DARWIN +// statically allocated thread local storage not supported in Darwin executable formats +#elif LL_WINDOWS +U32 __declspec(thread) sThreadID = 0; +#elif LL_LINUX +U32 __thread sThreadID = 0; #endif U32 LLThread::sIDIter = 0; + LL_COMMON_API void assert_main_thread() { static U32 s_thread_id = LLThread::currentID(); @@ -85,6 +93,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap { LLThread *threadp = (LLThread *)datap; + LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder(LLTrace::getUIThreadRecorder()); + #if !LL_DARWIN sThreadID = threadp->mID; #endif @@ -97,16 +107,18 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // We're done with the run function, this thread is done executing now. threadp->mStatus = STOPPED; + delete thread_recorder; + return NULL; } - LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : mPaused(FALSE), mName(name), mAPRThreadp(NULL), mStatus(STOPPED) { + mID = ++sIDIter; // Thread creation probably CAN be paranoid about APR being initialized, if necessary @@ -152,7 +164,7 @@ void LLThread::shutdown() //llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl; // Now wait a bit for the thread to exit // It's unclear whether I should even bother doing this - this destructor - // should netver get called unless we're already stopped, really... + // should never get called unless we're already stopped, really... S32 counter = 0; const S32 MAX_WAIT = 600; while (counter < MAX_WAIT) @@ -282,7 +294,13 @@ void LLThread::setQuitting() // static U32 LLThread::currentID() { +#if LL_DARWIN + // statically allocated thread local storage not supported in Darwin executable formats return (U32)apr_os_thread_current(); +#else + return sThreadID; +#endif + } // static @@ -315,155 +333,6 @@ void LLThread::wakeLocked() //============================================================================ -LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) -{ - //if (poolp) - //{ - // mIsLocalPool = FALSE; - // mAPRPoolp = poolp; - //} - //else - { - mIsLocalPool = TRUE; - apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread - } - apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); -} - - -LLMutex::~LLMutex() -{ -#if MUTEX_DEBUG - //bad assertion, the subclass LLSignal might be "locked", and that's OK - //llassert_always(!isLocked()); // better not be locked! -#endif - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; - if (mIsLocalPool) - { - apr_pool_destroy(mAPRPoolp); - } -} - - -void LLMutex::lock() -{ - if(isSelfLocked()) - { //redundant lock - mCount++; - return; - } - - apr_thread_mutex_lock(mAPRMutexp); - -#if MUTEX_DEBUG - // Have to have the lock before we can access the debug info - U32 id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) - llerrs << "Already locked in Thread: " << id << llendl; - mIsLocked[id] = TRUE; -#endif - -#if LL_DARWIN - mLockingThread = LLThread::currentID(); -#else - mLockingThread = sThreadID; -#endif -} - -void LLMutex::unlock() -{ - if (mCount > 0) - { //not the root unlock - mCount--; - return; - } - -#if MUTEX_DEBUG - // Access the debug info while we have the lock - U32 id = LLThread::currentID(); - if (mIsLocked[id] != TRUE) - llerrs << "Not locked in Thread: " << id << llendl; - mIsLocked[id] = FALSE; -#endif - - mLockingThread = NO_THREAD; - apr_thread_mutex_unlock(mAPRMutexp); -} - -bool LLMutex::isLocked() -{ - apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); - if (APR_STATUS_IS_EBUSY(status)) - { - return true; - } - else - { - apr_thread_mutex_unlock(mAPRMutexp); - return false; - } -} - -bool LLMutex::isSelfLocked() -{ -#if LL_DARWIN - return mLockingThread == LLThread::currentID(); -#else - return mLockingThread == sThreadID; -#endif -} - -U32 LLMutex::lockingThread() const -{ - return mLockingThread; -} - -//============================================================================ - -LLCondition::LLCondition(apr_pool_t *poolp) : - LLMutex(poolp) -{ - // base class (LLMutex) has already ensured that mAPRPoolp is set up. - - apr_thread_cond_create(&mAPRCondp, mAPRPoolp); -} - - -LLCondition::~LLCondition() -{ - apr_thread_cond_destroy(mAPRCondp); - mAPRCondp = NULL; -} - - -void LLCondition::wait() -{ - if (!isLocked()) - { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait - apr_thread_mutex_lock(mAPRMutexp); -#if MUTEX_DEBUG - // avoid asserts on destruction in non-release builds - U32 id = LLThread::currentID(); - mIsLocked[id] = TRUE; -#endif - } - apr_thread_cond_wait(mAPRCondp, mAPRMutexp); -} - -void LLCondition::signal() -{ - apr_thread_cond_signal(mAPRCondp); -} - -void LLCondition::broadcast() -{ - apr_thread_cond_broadcast(mAPRCondp); -} - -//============================================================================ - //---------------------------------------------------------------------------- //static @@ -514,7 +383,6 @@ LLThreadSafeRefCount::~LLThreadSafeRefCount() } } - //============================================================================ LLResponder::~LLResponder() diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 0fb89c5613..4a84a14a65 100755 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -31,20 +31,14 @@ #include "llapr.h" #include "apr_thread_cond.h" #include "boost/intrusive_ptr.hpp" +#include "llmutex.h" -class LLThread; -class LLMutex; -class LLCondition; - -#if LL_WINDOWS -#define ll_thread_local __declspec(thread) -#else -#define ll_thread_local __thread -#endif +LL_COMMON_API void assert_main_thread(); class LL_COMMON_API LLThread { private: + friend class LLMutex; static U32 sIDIter; public: @@ -98,15 +92,15 @@ private: BOOL mPaused; // static function passed to APR thread creation routine - static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); + static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap); protected: std::string mName; - LLCondition* mRunCondition; + class LLCondition* mRunCondition; LLMutex* mDataLock; - apr_thread_t *mAPRThreadp; - apr_pool_t *mAPRPoolp; + apr_thread_t* mAPRThreadp; + apr_pool_t* mAPRPoolp; BOOL mIsLocalPool; EThreadStatus mStatus; U32 mID; @@ -114,7 +108,7 @@ protected: //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. // otherwise it will cause severe memory leaking!!! --bao - LLVolatileAPRPool *mLocalAPRFilePoolp ; + LLVolatileAPRPool* mLocalAPRFilePoolp ; void setQuitting(); @@ -140,75 +134,6 @@ protected: // mDataLock->unlock(); }; -//============================================================================ - -#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) - -class LL_COMMON_API LLMutex -{ -public: - typedef enum - { - NO_THREAD = 0xFFFFFFFF - } e_locking_thread; - - LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex - virtual ~LLMutex(); - - void lock(); // blocks - void unlock(); - bool isLocked(); // non-blocking, but does do a lock/unlock so not free - bool isSelfLocked(); //return true if locked in a same thread - U32 lockingThread() const; //get ID of locking thread - -protected: - apr_thread_mutex_t *mAPRMutexp; - mutable U32 mCount; - mutable U32 mLockingThread; - - apr_pool_t *mAPRPoolp; - BOOL mIsLocalPool; - -#if MUTEX_DEBUG - std::map<U32, BOOL> mIsLocked; -#endif -}; - -// Actually a condition/mutex pair (since each condition needs to be associated with a mutex). -class LL_COMMON_API LLCondition : public LLMutex -{ -public: - LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. - ~LLCondition(); - - void wait(); // blocks - void signal(); - void broadcast(); - -protected: - apr_thread_cond_t *mAPRCondp; -}; - -class LLMutexLock -{ -public: - LLMutexLock(LLMutex* mutex) - { - mMutex = mutex; - - if(mMutex) - mMutex->lock(); - } - ~LLMutexLock() - { - if(mMutex) - mMutex->unlock(); - } -private: - LLMutex* mMutex; -}; - -//============================================================================ void LLThread::lockData() { diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp new file mode 100644 index 0000000000..32d94331a6 --- /dev/null +++ b/indra/llcommon/llthreadlocalstorage.cpp @@ -0,0 +1,117 @@ +/** + * @file llthreadlocalstorage.cpp + * @author Richard + * @date 2013-1-11 + * @brief implementation of thread local storage utility classes + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llthreadlocalstorage.h" +#include "llapr.h" + +// +//LLThreadLocalPointerBase +// +bool LLThreadLocalPointerBase::sInitialized = false; + +void LLThreadLocalPointerBase::set( void* value ) +{ + llassert(sInitialized && mThreadKey); + + apr_status_t result = apr_threadkey_private_set((void*)value, mThreadKey); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + llerrs << "Failed to set thread local data" << llendl; + } +} + +void* LLThreadLocalPointerBase::get() const +{ + // llassert(sInitialized); + void* ptr; + apr_status_t result = + apr_threadkey_private_get(&ptr, mThreadKey); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + llerrs << "Failed to get thread local data" << llendl; + } + return ptr; +} + + +void LLThreadLocalPointerBase::initStorage( ) +{ + apr_status_t result = apr_threadkey_private_create(&mThreadKey, NULL, gAPRPoolp); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + llerrs << "Failed to allocate thread local data" << llendl; + } +} + +void LLThreadLocalPointerBase::destroyStorage() +{ + if (sInitialized) + { + if (mThreadKey) + { + apr_status_t result = apr_threadkey_private_delete(mThreadKey); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + llerrs << "Failed to delete thread local data" << llendl; + } + } + } +} + +void LLThreadLocalPointerBase::initAllThreadLocalStorage() +{ + if (!sInitialized) + { + for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); + it != end_it; + ++it) + { + (*it).initStorage(); + } + sInitialized = true; + } +} + +void LLThreadLocalPointerBase::destroyAllThreadLocalStorage() +{ + if (sInitialized) + { + //for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); + // it != end_it; + // ++it) + //{ + // (*it).destroyStorage(); + //} + sInitialized = false; + } +} diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h new file mode 100644 index 0000000000..a15f9185b1 --- /dev/null +++ b/indra/llcommon/llthreadlocalstorage.h @@ -0,0 +1,357 @@ +/** + * @file llthreadlocalstorage.h + * @author Richard + * @brief Class wrappers for thread local storage + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTHREADLOCALSTORAGE_H +#define LL_LLTHREADLOCALSTORAGE_H + +#include "llinstancetracker.h" + +class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase> +{ +public: + LLThreadLocalPointerBase() + : mThreadKey(NULL) + { + if (sInitialized) + { + initStorage(); + } + } + + LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other) + : mThreadKey(NULL) + { + if (sInitialized) + { + initStorage(); + } + } + + ~LLThreadLocalPointerBase() + { + destroyStorage(); + } + + static void initAllThreadLocalStorage(); + static void destroyAllThreadLocalStorage(); + +protected: + void set(void* value); + + void* get() const; + + void initStorage(); + void destroyStorage(); + +protected: + struct apr_threadkey_t* mThreadKey; + static bool sInitialized; +}; + +template <typename T> +class LLThreadLocalPointer : public LLThreadLocalPointerBase +{ +public: + + LLThreadLocalPointer() + {} + + explicit LLThreadLocalPointer(T* value) + { + set(value); + } + + + LLThreadLocalPointer(const LLThreadLocalPointer<T>& other) + : LLThreadLocalPointerBase(other) + { + set(other.get()); + } + + LL_FORCE_INLINE T* get() const + { + return (T*)LLThreadLocalPointerBase::get(); + } + + T* operator -> () const + { + return (T*)get(); + } + + T& operator*() const + { + return *(T*)get(); + } + + LLThreadLocalPointer<T>& operator = (T* value) + { + set((void*)value); + return *this; + } + + bool operator ==(const T* other) const + { + if (!sInitialized) return false; + return get() == other; + } + + bool isNull() const { return !sInitialized || get() == NULL; } + + bool notNull() const { return sInitialized && get() != NULL; } +}; + +template<typename DERIVED_TYPE> +class LLThreadLocalSingleton +{ + typedef enum e_init_state + { + UNINITIALIZED = 0, + CONSTRUCTING, + INITIALIZING, + INITIALIZED, + DELETED + } EInitState; + +public: + LLThreadLocalSingleton() + {} + + virtual ~LLThreadLocalSingleton() + { +#if LL_DARWIN + pthread_setspecific(sInstanceKey, NULL); +#else + sInstance = NULL; +#endif + setInitState(DELETED); + } + + static void deleteSingleton() + { + delete getIfExists(); + } + + static DERIVED_TYPE* getInstance() + { + EInitState init_state = getInitState(); + if (init_state == CONSTRUCTING) + { + llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; + } + + if (init_state == DELETED) + { + llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; + } + +#if LL_DARWIN + createTLSInstance(); +#endif + if (!getIfExists()) + { + setInitState(CONSTRUCTING); + DERIVED_TYPE* instancep = new DERIVED_TYPE(); +#if LL_DARWIN + S32 result = pthread_setspecific(sInstanceKey, (void*)instancep); + if (result != 0) + { + llerrs << "Could not set thread local storage" << llendl; + } +#else + sInstance = instancep; +#endif + setInitState(INITIALIZING); + instancep->initSingleton(); + setInitState(INITIALIZED); + } + + return getIfExists(); + } + + static DERIVED_TYPE* getIfExists() + { +#if LL_DARWIN + return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey); +#else + return sInstance; +#endif + } + + // Reference version of getInstance() + // Preferred over getInstance() as it disallows checking for NULL + static DERIVED_TYPE& instance() + { + return *getInstance(); + } + + // Has this singleton been created uet? + // Use this to avoid accessing singletons before the can safely be constructed + static bool instanceExists() + { + return getInitState() == INITIALIZED; + } + + // Has this singleton already been deleted? + // Use this to avoid accessing singletons from a static object's destructor + static bool destroyed() + { + return getInitState() == DELETED; + } +private: +#if LL_DARWIN + static void createTLSInitState() + { + static S32 key_created = pthread_key_create(&sInitStateKey, NULL); + if (key_created != 0) + { + llerrs << "Could not create thread local storage" << llendl; + } + } + + static void createTLSInstance() + { + static S32 key_created = pthread_key_create(&sInstanceKey, NULL); + if (key_created != 0) + { + llerrs << "Could not create thread local storage" << llendl; + } + } +#endif + static EInitState getInitState() + { +#if LL_DARWIN + createTLSInitState(); + return (EInitState)(int)pthread_getspecific(sInitStateKey); +#else + return sInitState; +#endif + } + + static void setInitState(EInitState state) + { +#if LL_DARWIN + createTLSInitState(); + pthread_setspecific(sInitStateKey, (void*)state); +#else + sInitState = state; +#endif + } + LLThreadLocalSingleton(const LLThreadLocalSingleton& other); + virtual void initSingleton() {} + +#ifdef LL_WINDOWS + static __declspec(thread) DERIVED_TYPE* sInstance; + static __declspec(thread) EInitState sInitState; +#elif LL_LINUX + static __thread DERIVED_TYPE* sInstance; + static __thread EInitState sInitState; +#elif LL_DARWIN + static pthread_key_t sInstanceKey; + static pthread_key_t sInitStateKey; +#endif +}; + +#if LL_WINDOWS +template<typename DERIVED_TYPE> +__declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL; + +template<typename DERIVED_TYPE> +__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED; +#elif LL_LINUX +template<typename DERIVED_TYPE> +__thread DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL; + +template<typename DERIVED_TYPE> +__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED; +#elif LL_DARWIN +template<typename DERIVED_TYPE> +pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInstanceKey; + +template<typename DERIVED_TYPE> +pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInitStateKey; + +#endif + +template<typename DERIVED_TYPE> +class LLThreadLocalSingletonPointer +{ +public: + LL_FORCE_INLINE static DERIVED_TYPE* getInstance() + { +#if LL_DARWIN + createTLSKey(); + return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey); +#else + return sInstance; +#endif + } + + static void setInstance(DERIVED_TYPE* instance) + { +#if LL_DARWIN + createTLSKey(); + pthread_setspecific(sInstanceKey, (void*)instance); +#else + sInstance = instance; +#endif + } + +private: + +#if LL_WINDOWS + static __declspec(thread) DERIVED_TYPE* sInstance; +#elif LL_LINUX + static __thread DERIVED_TYPE* sInstance; +#elif LL_DARWIN + static void TLSError() + { + llerrs << "Could not create thread local storage" << llendl; + } + static void createTLSKey() + { + static S32 key_created = pthread_key_create(&sInstanceKey, NULL); + if (key_created != 0) + { + llerrs << "Could not create thread local storage" << llendl; + } + } + static pthread_key_t sInstanceKey; +#endif +}; + +#if LL_WINDOWS +template<typename DERIVED_TYPE> +__declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL; +#elif LL_LINUX +template<typename DERIVED_TYPE> +__thread DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL; +#elif LL_DARWIN +template<typename DERIVED_TYPE> +pthread_key_t LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstanceKey; +#endif + +#endif // LL_LLTHREADLOCALSTORAGE_H diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 9ebc6de7f4..693809b622 100755 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -31,11 +31,9 @@ #include "u64.h" #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> +# include "llwin32headerslean.h" #elif LL_LINUX || LL_SOLARIS || LL_DARWIN -# include <errno.h> +# include <errno.h> # include <sys/time.h> #else # error "architecture not supported" @@ -287,14 +285,14 @@ LLTimer::~LLTimer() } // static -U64 LLTimer::getTotalTime() +LLUnitImplicit<U64, LLUnits::Microseconds> LLTimer::getTotalTime() { // simply call into the implementation function. return totalTime(); } // static -F64 LLTimer::getTotalSeconds() +LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getTotalSeconds() { return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64; } @@ -343,23 +341,23 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount) } -F64 LLTimer::getElapsedTimeF64() const +LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getElapsedTimeF64() const { U64 last = mLastClockCount; return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv; } -F32 LLTimer::getElapsedTimeF32() const +LLUnitImplicit<F32, LLUnits::Seconds> LLTimer::getElapsedTimeF32() const { return (F32)getElapsedTimeF64(); } -F64 LLTimer::getElapsedTimeAndResetF64() +LLUnitImplicit<F64, LLUnits::Seconds> LLTimer::getElapsedTimeAndResetF64() { return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv; } -F32 LLTimer::getElapsedTimeAndResetF32() +LLUnitImplicit<F32, LLUnits::Seconds> LLTimer::getElapsedTimeAndResetF32() { return (F32)getElapsedTimeAndResetF64(); } @@ -372,7 +370,7 @@ void LLTimer::setTimerExpirySec(F32 expiration) + (U64)((F32)(expiration * gClockFrequency)); } -F32 LLTimer::getRemainingTimeF32() const +LLUnitImplicit<F32, LLUnits::Seconds> LLTimer::getRemainingTimeF32() const { U64 cur_ticks = get_clock_count(); if (cur_ticks > mExpirationTicks) diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 513de0605d..9e464c4b1a 100755 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -37,6 +37,7 @@ #include <string> #include <list> // units conversions +#include "llunit.h" #ifndef USEC_PER_SEC const U32 USEC_PER_SEC = 1000000; #endif @@ -55,7 +56,7 @@ public: protected: U64 mLastClockCount; U64 mExpirationTicks; - BOOL mStarted; + bool mStarted; public: LLTimer(); @@ -66,16 +67,16 @@ public: // Return a high precision number of seconds since the start of // this application instance. - static F64 getElapsedSeconds() + static LLUnitImplicit<F64, LLUnits::Seconds> getElapsedSeconds() { return sTimer->getElapsedTimeF64(); } // Return a high precision usec since epoch - static U64 getTotalTime(); + static LLUnitImplicit<U64, LLUnits::Microseconds> getTotalTime(); // Return a high precision seconds since epoch - static F64 getTotalSeconds(); + static LLUnitImplicit<F64, LLUnits::Seconds> getTotalSeconds(); // MANIPULATORS @@ -86,18 +87,18 @@ public: void setTimerExpirySec(F32 expiration); BOOL checkExpirationAndReset(F32 expiration); BOOL hasExpired() const; - F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset - F64 getElapsedTimeAndResetF64(); + LLUnitImplicit<F32, LLUnits::Seconds> getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset + LLUnitImplicit<F64, LLUnits::Seconds> getElapsedTimeAndResetF64(); - F32 getRemainingTimeF32() const; + LLUnitImplicit<F32, LLUnits::Seconds> getRemainingTimeF32() const; static BOOL knownBadTimer(); // ACCESSORS - F32 getElapsedTimeF32() const; // Returns elapsed time in seconds - F64 getElapsedTimeF64() const; // Returns elapsed time in seconds + LLUnitImplicit<F32, LLUnits::Seconds> getElapsedTimeF32() const; // Returns elapsed time in seconds + LLUnitImplicit<F64, LLUnits::Seconds> getElapsedTimeF64() const; // Returns elapsed time in seconds - BOOL getStarted() const { return mStarted; } + bool getStarted() const { return mStarted; } static U64 getCurrentClockCount(); // Returns the raw clockticks diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp new file mode 100644 index 0000000000..59a4b42c97 --- /dev/null +++ b/indra/llcommon/lltrace.cpp @@ -0,0 +1,116 @@ +/** + * @file lltrace.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltrace.h" +#include "lltracerecording.h" +#include "lltracethreadrecorder.h" +#include "llfasttimer.h" + +static S32 sInitializationCount = 0; + +namespace LLTrace +{ + +static MasterThreadRecorder* gUIThreadRecorder = NULL; + +void init() +{ + if (sInitializationCount++ == 0) + { + gUIThreadRecorder = new MasterThreadRecorder(); + } +} + +bool isInitialized() +{ + return sInitializationCount > 0; +} + +void cleanup() +{ + if (--sInitializationCount == 0) + { + delete gUIThreadRecorder; + gUIThreadRecorder = NULL; + } +} + +MasterThreadRecorder& getUIThreadRecorder() +{ + llassert(gUIThreadRecorder != NULL); + return *gUIThreadRecorder; +} + +LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr() +{ + static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder; + return s_thread_recorder; +} + +const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() +{ + return get_thread_recorder_ptr(); +} + +void set_thread_recorder(ThreadRecorder* recorder) +{ + get_thread_recorder_ptr() = recorder; +} + + +TimeBlockTreeNode::TimeBlockTreeNode() +: mBlock(NULL), + mParent(NULL), + mNeedsSorting(false), + mCollapsed(true) +{} + +void TimeBlockTreeNode::setParent( TimeBlock* parent ) +{ + llassert_always(parent != mBlock); + llassert_always(parent != NULL); + + TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(parent->getIndex()); + if (!parent_tree_node) return; + + if (mParent) + { + std::vector<TimeBlock*>& children = mParent->getChildren(); + std::vector<TimeBlock*>::iterator found_it = std::find(children.begin(), children.end(), mBlock); + if (found_it != children.end()) + { + children.erase(found_it); + } + } + + mParent = parent; + mBlock->getPrimaryAccumulator()->mParent = parent; + parent_tree_node->mChildren.push_back(mBlock); + parent_tree_node->mNeedsSorting = true; +} + +} diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h new file mode 100644 index 0000000000..fb7ffb0a29 --- /dev/null +++ b/indra/llcommon/lltrace.h @@ -0,0 +1,1099 @@ +/** + * @file lltrace.h + * @brief Runtime statistics accumulation. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRACE_H +#define LL_LLTRACE_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "llmemory.h" +#include "llrefcount.h" +#include "llunit.h" +#include "llthreadlocalstorage.h" +#include "lltimer.h" + +#include <list> + +#define LL_RECORD_BLOCK_TIME(block_timer) LLTrace::TimeBlock::Recorder LL_GLUE_TOKENS(block_time_recorder, __COUNTER__)(block_timer); + +namespace LLTrace +{ +class Recording; + +typedef LLUnit<F64, LLUnits::Bytes> Bytes; +typedef LLUnit<F64, LLUnits::Kibibytes> Kibibytes; +typedef LLUnit<F64, LLUnits::Mibibytes> Mibibytes; +typedef LLUnit<F64, LLUnits::Gibibytes> Gibibytes; +typedef LLUnit<F64, LLUnits::Bits> Bits; +typedef LLUnit<F64, LLUnits::Kibibits> Kibibits; +typedef LLUnit<F64, LLUnits::Mibibits> Mibibits; +typedef LLUnit<F64, LLUnits::Gibibits> Gibibits; + +typedef LLUnit<F64, LLUnits::Seconds> Seconds; +typedef LLUnit<F64, LLUnits::Milliseconds> Milliseconds; +typedef LLUnit<F64, LLUnits::Minutes> Minutes; +typedef LLUnit<F64, LLUnits::Hours> Hours; +typedef LLUnit<F64, LLUnits::Milliseconds> Milliseconds; +typedef LLUnit<F64, LLUnits::Microseconds> Microseconds; +typedef LLUnit<F64, LLUnits::Nanoseconds> Nanoseconds; + +typedef LLUnit<F64, LLUnits::Meters> Meters; +typedef LLUnit<F64, LLUnits::Kilometers> Kilometers; +typedef LLUnit<F64, LLUnits::Centimeters> Centimeters; +typedef LLUnit<F64, LLUnits::Millimeters> Millimeters; + + +template<typename T> +T storage_value(T val) { return val; } + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +STORAGE_TYPE storage_value(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +STORAGE_TYPE storage_value(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } + +void init(); +void cleanup(); +bool isInitialized(); + +const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder(); +void set_thread_recorder(class ThreadRecorder*); + +class MasterThreadRecorder& getUIThreadRecorder(); + +template<typename ACCUMULATOR> +class AccumulatorBuffer : public LLRefCount +{ + typedef AccumulatorBuffer<ACCUMULATOR> self_t; + static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64; +private: + struct StaticAllocationMarker { }; + + AccumulatorBuffer(StaticAllocationMarker m) + : mStorageSize(0), + mStorage(NULL) + {} + +public: + + AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer()) + : mStorageSize(0), + mStorage(NULL) + { + resize(other.mStorageSize); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + ~AccumulatorBuffer() + { + if (isPrimary()) + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); + } + delete[] mStorage; + } + + LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) + { + return mStorage[index]; + } + + LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const + { + return mStorage[index]; + } + + void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, bool append = true) + { + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].addSamples(other.mStorage[i], append); + } + } + + void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) + { + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL) + { + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].reset(other ? &other->mStorage[i] : NULL); + } + } + + void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) + { + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].flush(time_stamp); + } + } + + void makePrimary() + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); + } + + bool isPrimary() const + { + return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; + } + + LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage() + { + ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance(); + return accumulator ? accumulator : getDefaultBuffer()->mStorage; + } + + // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned + size_t reserveSlot() + { +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (LLTrace::isInitialized()) + { + llerrs << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << llendl; + } +#endif + size_t next_slot = sNextStorageSlot++; + if (next_slot >= mStorageSize) + { + resize(mStorageSize + (mStorageSize >> 2)); + } + llassert(mStorage && next_slot < mStorageSize); + return next_slot; + } + + void resize(size_t new_size) + { + if (new_size <= mStorageSize) return; + + ACCUMULATOR* old_storage = mStorage; + mStorage = new ACCUMULATOR[new_size]; + if (old_storage) + { + for (S32 i = 0; i < mStorageSize; i++) + { + mStorage[i] = old_storage[i]; + } + } + mStorageSize = new_size; + delete[] old_storage; + + self_t* default_buffer = getDefaultBuffer(); + if (this != default_buffer + && new_size > default_buffer->size()) + { + //NB: this is not thread safe, but we assume that all resizing occurs during static initialization + default_buffer->resize(new_size); + } + } + + size_t size() const + { + return getNumIndices(); + } + + static size_t getNumIndices() + { + return sNextStorageSlot; + } + + static self_t* getDefaultBuffer() + { + static bool sInitialized = false; + if (!sInitialized) + { + // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data + // so as not to trigger an access violation + sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); + sInitialized = true; + sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); + } + return sDefaultBuffer; + } + +private: + ACCUMULATOR* mStorage; + size_t mStorageSize; + static size_t sNextStorageSlot; + static self_t* sDefaultBuffer; +}; + +template<typename ACCUMULATOR> size_t AccumulatorBuffer<ACCUMULATOR>::sNextStorageSlot = 0; +template<typename ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>* AccumulatorBuffer<ACCUMULATOR>::sDefaultBuffer = NULL; + +template<typename ACCUMULATOR> +class TraceType +: public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string> +{ +public: + TraceType(const char* name, const char* description = NULL) + : LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>(name), + mName(name), + mDescription(description ? description : ""), + mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot()) + {} + + LL_FORCE_INLINE ACCUMULATOR* getPrimaryAccumulator() const + { + ACCUMULATOR* accumulator_storage = AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage(); + return &accumulator_storage[mAccumulatorIndex]; + } + + size_t getIndex() const { return mAccumulatorIndex; } + static size_t getNumIndices() { return AccumulatorBuffer<ACCUMULATOR>::getNumIndices(); } + + virtual const char* getUnitLabel() { return ""; } + + const std::string& getName() const { return mName; } + +protected: + const std::string mName; + const std::string mDescription; + const size_t mAccumulatorIndex; +}; + +class EventAccumulator +{ +public: + typedef F64 value_t; + typedef F64 mean_t; + + EventAccumulator() + : mSum(0), + mMin((std::numeric_limits<F64>::max)()), + mMax((std::numeric_limits<F64>::min)()), + mMean(0), + mVarianceSum(0), + mNumSamples(0), + mLastValue(0) + {} + + void record(F64 value) + { + mNumSamples++; + mSum += value; + // NOTE: both conditions will hold on first pass through + if (value < mMin) + { + mMin = value; + } + if (value > mMax) + { + mMax = value; + } + F64 old_mean = mMean; + mMean += (value - old_mean) / (F64)mNumSamples; + mVarianceSum += (value - old_mean) * (value - mMean); + mLastValue = value; + } + + void addSamples(const EventAccumulator& other, bool append) + { + if (other.mNumSamples) + { + mSum += other.mSum; + + // NOTE: both conditions will hold first time through + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = (F64)mNumSamples, + n_2 = (F64)other.mNumSamples; + F64 m_1 = mMean, + m_2 = other.mMean; + F64 v_1 = mVarianceSum / mNumSamples, + v_2 = other.mVarianceSum / other.mNumSamples; + if (n_1 == 0) + { + mVarianceSum = other.mVarianceSum; + } + else if (n_2 == 0) + { + // don't touch variance + // mVarianceSum = mVarianceSum; + } + else + { + mVarianceSum = (F64)mNumSamples + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); + } + + F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); + mNumSamples += other.mNumSamples; + mMean = mMean * weight + other.mMean * (1.f - weight); + if (append) mLastValue = other.mLastValue; + } + } + + void reset(const EventAccumulator* other) + { + mNumSamples = 0; + mSum = 0; + mMin = std::numeric_limits<F64>::max(); + mMax = std::numeric_limits<F64>::min(); + mMean = 0; + mVarianceSum = 0; + mLastValue = other ? other->mLastValue : 0; + } + + void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {} + + F64 getSum() const { return mSum; } + F64 getMin() const { return mMin; } + F64 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); } + U32 getSampleCount() const { return mNumSamples; } + +private: + F64 mSum, + mMin, + mMax, + mLastValue; + + F64 mMean, + mVarianceSum; + + U32 mNumSamples; +}; + + +class SampleAccumulator +{ +public: + typedef F64 value_t; + typedef F64 mean_t; + + SampleAccumulator() + : mSum(0), + mMin((std::numeric_limits<F64>::max)()), + mMax((std::numeric_limits<F64>::min)()), + mMean(0), + mVarianceSum(0), + mLastSampleTimeStamp(LLTimer::getTotalSeconds()), + mTotalSamplingTime(0), + mNumSamples(0), + mLastValue(0), + mHasValue(false) + {} + + void sample(F64 value) + { + LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); + LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp; + mLastSampleTimeStamp = time_stamp; + + if (mHasValue) + { + mTotalSamplingTime += delta_time; + mSum += mLastValue * delta_time; + + // NOTE: both conditions will hold first time through + if (value < mMin) { mMin = value; } + if (value > mMax) { mMax = value; } + + F64 old_mean = mMean; + mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); + mVarianceSum += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); + } + + mLastValue = value; + mNumSamples++; + mHasValue = true; + } + + void addSamples(const SampleAccumulator& other, bool append) + { + if (other.mTotalSamplingTime) + { + mSum += other.mSum; + + // NOTE: both conditions will hold first time through + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = mTotalSamplingTime, + n_2 = other.mTotalSamplingTime; + F64 m_1 = mMean, + m_2 = other.mMean; + F64 v_1 = mVarianceSum / mTotalSamplingTime, + v_2 = other.mVarianceSum / other.mTotalSamplingTime; + if (n_1 == 0) + { + mVarianceSum = other.mVarianceSum; + } + else if (n_2 == 0) + { + // variance is unchanged + // mVarianceSum = mVarianceSum; + } + else + { + mVarianceSum = mTotalSamplingTime + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); + } + + llassert(other.mTotalSamplingTime > 0); + F64 weight = mTotalSamplingTime / (mTotalSamplingTime + other.mTotalSamplingTime); + mNumSamples += other.mNumSamples; + mTotalSamplingTime += other.mTotalSamplingTime; + mMean = (mMean * weight) + (other.mMean * (1.0 - weight)); + if (append) + { + mLastValue = other.mLastValue; + mLastSampleTimeStamp = other.mLastSampleTimeStamp; + mHasValue |= other.mHasValue; + } + } + } + + void reset(const SampleAccumulator* other) + { + mNumSamples = 0; + mSum = 0; + mMin = std::numeric_limits<F64>::max(); + mMax = std::numeric_limits<F64>::min(); + mMean = other ? other->mLastValue : 0; + mVarianceSum = 0; + mLastSampleTimeStamp = LLTimer::getTotalSeconds(); + mTotalSamplingTime = 0; + mLastValue = other ? other->mLastValue : 0; + mHasValue = other ? other->mHasValue : false; + } + + void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) + { + LLUnitImplicit<F64, LLUnits::Seconds> delta_time = time_stamp - mLastSampleTimeStamp; + + if (mHasValue) + { + mSum += mLastValue * delta_time; + mTotalSamplingTime += delta_time; + } + mLastSampleTimeStamp = time_stamp; + } + + F64 getSum() const { return mSum; } + F64 getMin() const { return mMin; } + F64 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mTotalSamplingTime); } + U32 getSampleCount() const { return mNumSamples; } + +private: + F64 mSum, + mMin, + mMax, + mLastValue; + + bool mHasValue; + + F64 mMean, + mVarianceSum; + + LLUnitImplicit<F64, LLUnits::Seconds> mLastSampleTimeStamp, + mTotalSamplingTime; + + U32 mNumSamples; +}; + +class CountAccumulator +{ +public: + typedef F64 value_t; + typedef F64 mean_t; + + CountAccumulator() + : mSum(0), + mNumSamples(0) + {} + + void add(F64 value) + { + mNumSamples++; + mSum += value; + } + + void addSamples(const CountAccumulator& other, bool /*append*/) + { + mSum += other.mSum; + mNumSamples += other.mNumSamples; + } + + void reset(const CountAccumulator* other) + { + mNumSamples = 0; + mSum = 0; + } + + void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {} + + F64 getSum() const { return mSum; } + + U32 getSampleCount() const { return mNumSamples; } + +private: + F64 mSum; + + U32 mNumSamples; +}; + +class TimeBlockAccumulator +{ +public: + typedef LLUnit<F64, LLUnits::Seconds> value_t; + typedef LLUnit<F64, LLUnits::Seconds> mean_t; + typedef TimeBlockAccumulator self_t; + + // fake classes that allows us to view different facets of underlying statistic + struct CallCountFacet + { + typedef U32 value_t; + typedef F32 mean_t; + }; + + struct SelfTimeFacet + { + typedef LLUnit<F64, LLUnits::Seconds> value_t; + typedef LLUnit<F64, LLUnits::Seconds> mean_t; + }; + + TimeBlockAccumulator(); + void addSamples(const self_t& other, bool /*append*/); + void reset(const self_t* other); + void flush(LLUnitImplicit<F64, LLUnits::Seconds>) {} + + // + // members + // + U64 mStartTotalTimeCounter, + mTotalTimeCounter, + mSelfTimeCounter; + U32 mCalls; + class TimeBlock* mParent; // last acknowledged parent of this time block + class TimeBlock* mLastCaller; // used to bootstrap tree construction + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + +}; + +template<> +class TraceType<TimeBlockAccumulator::CallCountFacet> +: public TraceType<TimeBlockAccumulator> +{ +public: + + TraceType(const char* name, const char* description = "") + : TraceType<TimeBlockAccumulator>(name, description) + {} +}; + +template<> +class TraceType<TimeBlockAccumulator::SelfTimeFacet> + : public TraceType<TimeBlockAccumulator> +{ +public: + + TraceType(const char* name, const char* description = "") + : TraceType<TimeBlockAccumulator>(name, description) + {} +}; + +class TimeBlock; +class TimeBlockTreeNode +{ +public: + TimeBlockTreeNode(); + + void setParent(TimeBlock* parent); + TimeBlock* getParent() { return mParent; } + + TimeBlock* mBlock; + TimeBlock* mParent; + std::vector<TimeBlock*> mChildren; + bool mCollapsed; + bool mNeedsSorting; +}; + + +template <typename T = F64> +class EventStatHandle +: public TraceType<EventAccumulator> +{ +public: + typedef F64 storage_t; + typedef TraceType<EventAccumulator> trace_t; + + EventStatHandle(const char* name, const char* description = NULL) + : trace_t(name, description) + {} + + /*virtual*/ const char* getUnitLabel() { return LLGetUnitLabel<T>::getUnitLabel(); } + +}; + +template<typename T, typename VALUE_T> +void record(EventStatHandle<T>& measurement, VALUE_T value) +{ + T converted_value(value); + measurement.getPrimaryAccumulator()->record(storage_value(converted_value)); +} + +template <typename T = F64> +class SampleStatHandle +: public TraceType<SampleAccumulator> +{ +public: + typedef F64 storage_t; + typedef TraceType<SampleAccumulator> trace_t; + + SampleStatHandle(const char* name, const char* description = NULL) + : trace_t(name, description) + {} + + /*virtual*/ const char* getUnitLabel() { return LLGetUnitLabel<T>::getUnitLabel(); } +}; + +template<typename T, typename VALUE_T> +void sample(SampleStatHandle<T>& measurement, VALUE_T value) +{ + T converted_value(value); + measurement.getPrimaryAccumulator()->sample(storage_value(converted_value)); +} + +template <typename T = F64> +class CountStatHandle +: public TraceType<CountAccumulator> +{ +public: + typedef F64 storage_t; + typedef TraceType<CountAccumulator> trace_t; + + CountStatHandle(const char* name, const char* description = NULL) + : trace_t(name) + {} + + /*virtual*/ const char* getUnitLabel() { return LLGetUnitLabel<T>::getUnitLabel(); } +}; + +template<typename T, typename VALUE_T> +void add(CountStatHandle<T>& count, VALUE_T value) +{ + T converted_value(value); + count.getPrimaryAccumulator()->add(storage_value(converted_value)); +} + + +struct MemStatAccumulator +{ + typedef MemStatAccumulator self_t; + + // fake classes that allows us to view different facets of underlying statistic + struct AllocationCountFacet + { + typedef U32 value_t; + typedef F32 mean_t; + }; + + struct DeallocationCountFacet + { + typedef U32 value_t; + typedef F32 mean_t; + }; + + struct ChildMemFacet + { + typedef LLUnit<F64, LLUnits::Bytes> value_t; + typedef LLUnit<F64, LLUnits::Bytes> mean_t; + }; + + MemStatAccumulator() + : mAllocatedCount(0), + mDeallocatedCount(0) + {} + + void addSamples(const MemStatAccumulator& other, bool append) + { + mSize.addSamples(other.mSize, append); + mChildSize.addSamples(other.mChildSize, append); + mAllocatedCount += other.mAllocatedCount; + mDeallocatedCount += other.mDeallocatedCount; + } + + void reset(const MemStatAccumulator* other) + { + mSize.reset(other ? &other->mSize : NULL); + mChildSize.reset(other ? &other->mChildSize : NULL); + mAllocatedCount = 0; + mDeallocatedCount = 0; + } + + void flush(LLUnitImplicit<F64, LLUnits::Seconds> time_stamp) + { + mSize.flush(time_stamp); + mChildSize.flush(time_stamp); + } + + SampleAccumulator mSize, + mChildSize; + int mAllocatedCount, + mDeallocatedCount; +}; + + +template<> +class TraceType<MemStatAccumulator::AllocationCountFacet> +: public TraceType<MemStatAccumulator> +{ +public: + + TraceType(const char* name, const char* description = "") + : TraceType<MemStatAccumulator>(name, description) + {} +}; + +template<> +class TraceType<MemStatAccumulator::DeallocationCountFacet> +: public TraceType<MemStatAccumulator> +{ +public: + + TraceType(const char* name, const char* description = "") + : TraceType<MemStatAccumulator>(name, description) + {} +}; + +template<> +class TraceType<MemStatAccumulator::ChildMemFacet> + : public TraceType<MemStatAccumulator> +{ +public: + + TraceType(const char* name, const char* description = "") + : TraceType<MemStatAccumulator>(name, description) + {} +}; + +class MemStatHandle : public TraceType<MemStatAccumulator> +{ +public: + typedef TraceType<MemStatAccumulator> trace_t; + MemStatHandle(const char* name) + : trace_t(name) + {} + + /*virtual*/ const char* getUnitLabel() { return "B"; } + + TraceType<MemStatAccumulator::AllocationCountFacet>& allocationCount() + { + return static_cast<TraceType<MemStatAccumulator::AllocationCountFacet>&>(*(TraceType<MemStatAccumulator>*)this); + } + + TraceType<MemStatAccumulator::DeallocationCountFacet>& deallocationCount() + { + return static_cast<TraceType<MemStatAccumulator::DeallocationCountFacet>&>(*(TraceType<MemStatAccumulator>*)this); + } + + TraceType<MemStatAccumulator::ChildMemFacet>& childMem() + { + return static_cast<TraceType<MemStatAccumulator::ChildMemFacet>&>(*(TraceType<MemStatAccumulator>*)this); + } +}; + +// measures effective memory footprint of specified type +// specialize to cover different types + +template<typename T> +struct MemFootprint +{ + static size_t measure(const T& value) + { + return sizeof(T); + } + + static size_t measure() + { + return sizeof(T); + } +}; + +template<typename T> +struct MemFootprint<T*> +{ + static size_t measure(const T* value) + { + if (!value) + { + return 0; + } + return MemFootprint<T>::measure(*value); + } + + static size_t measure() + { + return MemFootprint<T>::measure(); + } +}; + +template<typename T> +struct MemFootprint<std::basic_string<T> > +{ + static size_t measure(const std::basic_string<T>& value) + { + return value.capacity() * sizeof(T); + } + + static size_t measure() + { + return sizeof(std::basic_string<T>); + } +}; + +template<typename T> +struct MemFootprint<std::vector<T> > +{ + static size_t measure(const std::vector<T>& value) + { + return value.capacity() * MemFootprint<T>::measure(); + } + + static size_t measure() + { + return sizeof(std::vector<T>); + } +}; + +template<typename T> +struct MemFootprint<std::list<T> > +{ + static size_t measure(const std::list<T>& value) + { + return value.size() * (MemFootprint<T>::measure() + sizeof(void*) * 2); + } + + static size_t measure() + { + return sizeof(std::list<T>); + } +}; + +template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN> +class MemTrackable +{ + template<typename TRACKED, typename TRACKED_IS_TRACKER> + struct TrackMemImpl; + + typedef MemTrackable<DERIVED> mem_trackable_t; + +public: + typedef void mem_trackable_tag_t; + + virtual ~MemTrackable() + { + memDisclaim(mMemFootprint); + } + + void* operator new(size_t size) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)size); + accumulator->mAllocatedCount++; + } + + return ::operator new(size); + } + + void operator delete(void* ptr, size_t size) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)size); + accumulator->mAllocatedCount--; + accumulator->mDeallocatedCount++; + } + ::operator delete(ptr); + } + + void *operator new [](size_t size) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)size); + accumulator->mAllocatedCount++; + } + + return ::operator new[](size); + } + + void operator delete[](void* ptr, size_t size) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)size); + accumulator->mAllocatedCount--; + accumulator->mDeallocatedCount++; + } + ::operator delete[](ptr); + } + + // claim memory associated with other objects/data as our own, adding to our calculated footprint + template<typename CLAIM_T> + CLAIM_T& memClaim(CLAIM_T& value) + { + TrackMemImpl<CLAIM_T>::claim(*this, value); + return value; + } + + template<typename CLAIM_T> + const CLAIM_T& memClaim(const CLAIM_T& value) + { + TrackMemImpl<CLAIM_T>::claim(*this, value); + return value; + } + + + void memClaimAmount(size_t size) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + mMemFootprint += size; + if (accumulator) + { + accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)size); + } + } + + // remove memory we had claimed from our calculated footprint + template<typename CLAIM_T> + CLAIM_T& memDisclaim(CLAIM_T& value) + { + TrackMemImpl<CLAIM_T>::disclaim(*this, value); + return value; + } + + template<typename CLAIM_T> + const CLAIM_T& memDisclaim(const CLAIM_T& value) + { + TrackMemImpl<CLAIM_T>::disclaim(*this, value); + return value; + } + + void memDisclaimAmount(size_t size) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)size); + } + } + +private: + size_t mMemFootprint; + + template<typename TRACKED, typename TRACKED_IS_TRACKER = void> + struct TrackMemImpl + { + static void claim(mem_trackable_t& tracker, const TRACKED& tracked) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + size_t footprint = MemFootprint<TRACKED>::measure(tracked); + accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)footprint); + tracker.mMemFootprint += footprint; + } + } + + static void disclaim(mem_trackable_t& tracker, const TRACKED& tracked) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + size_t footprint = MemFootprint<TRACKED>::measure(tracked); + accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)footprint); + tracker.mMemFootprint -= footprint; + } + } + }; + + template<typename TRACKED> + struct TrackMemImpl<TRACKED, typename TRACKED::mem_trackable_tag_t> + { + static void claim(mem_trackable_t& tracker, TRACKED& tracked) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + accumulator->mChildSize.sample(accumulator->mChildSize.getLastValue() + (F64)MemFootprint<TRACKED>::measure(tracked)); + } + } + + static void disclaim(mem_trackable_t& tracker, TRACKED& tracked) + { + MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator(); + if (accumulator) + { + accumulator->mChildSize.sample(accumulator->mChildSize.getLastValue() - (F64)MemFootprint<TRACKED>::measure(tracked)); + } + } + }; +}; + +} +#endif // LL_LLTRACE_H diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp new file mode 100644 index 0000000000..d34434f161 --- /dev/null +++ b/indra/llcommon/lltracerecording.cpp @@ -0,0 +1,914 @@ +/** + * @file lltracesampler.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltrace.h" +#include "llfasttimer.h" +#include "lltracerecording.h" +#include "lltracethreadrecorder.h" +#include "llthread.h" + +namespace LLTrace +{ + + +/////////////////////////////////////////////////////////////////////// +// RecordingBuffers +/////////////////////////////////////////////////////////////////////// + +RecordingBuffers::RecordingBuffers() +{} + +void RecordingBuffers::handOffTo(RecordingBuffers& other) +{ + other.mCounts.reset(&mCounts); + other.mSamples.reset(&mSamples); + other.mEvents.reset(&mEvents); + other.mStackTimers.reset(&mStackTimers); + other.mMemStats.reset(&mMemStats); +} + +void RecordingBuffers::makePrimary() +{ + mCounts.makePrimary(); + mSamples.makePrimary(); + mEvents.makePrimary(); + mStackTimers.makePrimary(); + mMemStats.makePrimary(); + + ThreadRecorder* thread_recorder = get_thread_recorder().get(); + AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers; + // update stacktimer parent pointers + for (S32 i = 0, end_i = mStackTimers.size(); i < end_i; i++) + { + TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i); + if (tree_node) + { + timer_accumulator_buffer[i].mParent = tree_node->mParent; + } + } +} + +bool RecordingBuffers::isPrimary() const +{ + return mCounts.isPrimary(); +} + +void RecordingBuffers::append( const RecordingBuffers& other ) +{ + mCounts.addSamples(other.mCounts); + mSamples.addSamples(other.mSamples); + mEvents.addSamples(other.mEvents); + mMemStats.addSamples(other.mMemStats); + mStackTimers.addSamples(other.mStackTimers); +} + +void RecordingBuffers::merge( const RecordingBuffers& other) +{ + mCounts.addSamples(other.mCounts, false); + mSamples.addSamples(other.mSamples, false); + mEvents.addSamples(other.mEvents, false); + mMemStats.addSamples(other.mMemStats, false); + // for now, hold out timers from merge, need to be displayed per thread + //mStackTimers.addSamples(other.mStackTimers, false); +} + +void RecordingBuffers::reset(RecordingBuffers* other) +{ + mCounts.reset(other ? &other->mCounts : NULL); + mSamples.reset(other ? &other->mSamples : NULL); + mEvents.reset(other ? &other->mEvents : NULL); + mStackTimers.reset(other ? &other->mStackTimers : NULL); + mMemStats.reset(other ? &other->mMemStats : NULL); +} + +void RecordingBuffers::flush() +{ + LLUnitImplicit<F64, LLUnits::Seconds> time_stamp = LLTimer::getTotalSeconds(); + + mSamples.flush(time_stamp); +} + +/////////////////////////////////////////////////////////////////////// +// Recording +/////////////////////////////////////////////////////////////////////// + +Recording::Recording() +: mElapsedSeconds(0) +{ + mBuffers = new RecordingBuffers(); +} + +Recording::Recording( const Recording& other ) +{ + *this = other; +} + +Recording& Recording::operator = (const Recording& other) +{ + // this will allow us to seamlessly start without affecting any data we've acquired from other + setPlayState(PAUSED); + + Recording& mutable_other = const_cast<Recording&>(other); + mutable_other.update(); + EPlayState other_play_state = other.getPlayState(); + + mBuffers = mutable_other.mBuffers; + + LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state); + + // above call will clear mElapsedSeconds as a side effect, so copy it here + mElapsedSeconds = other.mElapsedSeconds; + mSamplingTimer = other.mSamplingTimer; + return *this; +} + + +Recording::~Recording() +{ + if (isStarted() && LLTrace::get_thread_recorder().notNull()) + { + LLTrace::get_thread_recorder()->deactivate(this); + } +} + +void Recording::update() +{ + if (isStarted()) + { + mBuffers.write()->flush(); + LLTrace::get_thread_recorder()->bringUpToDate(this); + mSamplingTimer.reset(); + } +} + +void Recording::handleReset() +{ + mBuffers.write()->reset(); + + mElapsedSeconds = 0.0; + mSamplingTimer.reset(); +} + +void Recording::handleStart() +{ + mSamplingTimer.reset(); + LLTrace::get_thread_recorder()->activate(this); +} + +void Recording::handleStop() +{ + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + mBuffers.write()->flush(); + LLTrace::get_thread_recorder()->deactivate(this); +} + +void Recording::handleSplitTo(Recording& other) +{ + mBuffers.write()->handOffTo(*other.mBuffers.write()); +} + +void Recording::appendRecording( const Recording& other ) +{ + update(); + mBuffers.write()->append(*other.mBuffers); + mElapsedSeconds += other.mElapsedSeconds; +} + +void Recording::mergeRecording( const Recording& other) +{ + update(); + mBuffers.write()->merge(*other.mBuffers); +} + +LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter) + / (F64)LLTrace::TimeBlock::countsPerSecond(); +} + +LLUnit<F64, LLUnits::Seconds> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + return (F64)(accumulator.mSelfTimeCounter) / (F64)LLTrace::TimeBlock::countsPerSecond(); +} + + +U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat) +{ + return mBuffers->mStackTimers[stat.getIndex()].mCalls; +} + +LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + + return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter) + / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value()); +} + +LLUnit<F64, LLUnits::Seconds> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat) +{ + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + + return (F64)(accumulator.mSelfTimeCounter) + / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds.value()); +} + +F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat) +{ + return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds.value(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mSize.getMin(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mSize.getMean(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mSize.getMax(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mSize.getStandardDeviation(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getLastValue(const TraceType<MemStatAccumulator>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mSize.getLastValue(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMin(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMean(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMax(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getStandardDeviation(); +} + +LLUnit<F64, LLUnits::Bytes> Recording::getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mChildSize.getLastValue(); +} + +U32 Recording::getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount; +} + +U32 Recording::getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat) +{ + return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount; +} + + +F64 Recording::getSum( const TraceType<CountAccumulator>& stat ) +{ + return mBuffers->mCounts[stat.getIndex()].getSum(); +} + +F64 Recording::getSum( const TraceType<EventAccumulator>& stat ) +{ + return (F64)mBuffers->mEvents[stat.getIndex()].getSum(); +} + +F64 Recording::getPerSec( const TraceType<CountAccumulator>& stat ) +{ + F64 sum = mBuffers->mCounts[stat.getIndex()].getSum(); + return (sum != 0.0) + ? (sum / mElapsedSeconds.value()) + : 0.0; +} + +U32 Recording::getSampleCount( const TraceType<CountAccumulator>& stat ) +{ + return mBuffers->mCounts[stat.getIndex()].getSampleCount(); +} + +F64 Recording::getMin( const TraceType<SampleAccumulator>& stat ) +{ + return mBuffers->mSamples[stat.getIndex()].getMin(); +} + +F64 Recording::getMax( const TraceType<SampleAccumulator>& stat ) +{ + return mBuffers->mSamples[stat.getIndex()].getMax(); +} + +F64 Recording::getMean( const TraceType<SampleAccumulator>& stat ) +{ + return mBuffers->mSamples[stat.getIndex()].getMean(); +} + +F64 Recording::getStandardDeviation( const TraceType<SampleAccumulator>& stat ) +{ + return mBuffers->mSamples[stat.getIndex()].getStandardDeviation(); +} + +F64 Recording::getLastValue( const TraceType<SampleAccumulator>& stat ) +{ + return mBuffers->mSamples[stat.getIndex()].getLastValue(); +} + +U32 Recording::getSampleCount( const TraceType<SampleAccumulator>& stat ) +{ + return mBuffers->mSamples[stat.getIndex()].getSampleCount(); +} + +F64 Recording::getMin( const TraceType<EventAccumulator>& stat ) +{ + return mBuffers->mEvents[stat.getIndex()].getMin(); +} + +F64 Recording::getMax( const TraceType<EventAccumulator>& stat ) +{ + return mBuffers->mEvents[stat.getIndex()].getMax(); +} + +F64 Recording::getMean( const TraceType<EventAccumulator>& stat ) +{ + return mBuffers->mEvents[stat.getIndex()].getMean(); +} + +F64 Recording::getStandardDeviation( const TraceType<EventAccumulator>& stat ) +{ + return mBuffers->mEvents[stat.getIndex()].getStandardDeviation(); +} + +F64 Recording::getLastValue( const TraceType<EventAccumulator>& stat ) +{ + return mBuffers->mEvents[stat.getIndex()].getLastValue(); +} + +U32 Recording::getSampleCount( const TraceType<EventAccumulator>& stat ) +{ + return mBuffers->mEvents[stat.getIndex()].getSampleCount(); +} + +/////////////////////////////////////////////////////////////////////// +// PeriodicRecording +/////////////////////////////////////////////////////////////////////// + +PeriodicRecording::PeriodicRecording( U32 num_periods, EPlayState state) +: mAutoResize(num_periods == 0), + mCurPeriod(0), + mNumPeriods(0), + mRecordingPeriods(num_periods ? num_periods : 1) +{ + setPlayState(state); +} + +void PeriodicRecording::nextPeriod() +{ + if (mAutoResize) + { + mRecordingPeriods.push_back(Recording()); + } + + Recording& old_recording = getCurRecording(); + mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size(); + old_recording.splitTo(getCurRecording()); + + mNumPeriods = llmin(mRecordingPeriods.size(), mNumPeriods + 1); +} + +void PeriodicRecording::appendRecording(Recording& recording) +{ + getCurRecording().appendRecording(recording); + nextPeriod(); +} + + +void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) +{ + if (other.mRecordingPeriods.empty()) return; + + getCurRecording().update(); + other.getCurRecording().update(); + + const U32 other_recording_slots = other.mRecordingPeriods.size(); + const U32 other_num_recordings = other.getNumRecordedPeriods(); + const U32 other_current_recording_index = other.mCurPeriod; + const U32 other_oldest_recording_index = (other_current_recording_index + other_recording_slots - other_num_recordings + 1) % other_recording_slots; + + // append first recording into our current slot + getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); + + // from now on, add new recordings for everything after the first + U32 other_index = (other_oldest_recording_index + 1) % other_recording_slots; + + if (mAutoResize) + { + // append first recording into our current slot + getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); + + // push back recordings for everything in the middle + U32 other_index = (other_oldest_recording_index + 1) % other_recording_slots; + while (other_index != other_current_recording_index) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); + other_index = (other_index + 1) % other_recording_slots; + } + + // add final recording, if it wasn't already added as the first + if (other_num_recordings > 1) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]); + } + + mCurPeriod = mRecordingPeriods.size() - 1; + mNumPeriods = mRecordingPeriods.size(); + } + else + { + size_t num_to_copy = llmin( mRecordingPeriods.size(), (size_t)other_num_recordings); + + std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin() + other_index ; + std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + mCurPeriod; + + // already consumed the first recording from other, so start counting at 1 + for(size_t i = 1; i < num_to_copy; i++) + { + *dest_it = *src_it; + + if (++src_it == other.mRecordingPeriods.end()) + { + src_it = other.mRecordingPeriods.begin(); + } + + if (++dest_it == mRecordingPeriods.end()) + { + dest_it = mRecordingPeriods.begin(); + } + } + + // want argument to % to be positive, otherwise result could be negative and thus out of bounds + llassert(num_to_copy >= 1); + // advance to last recording period copied, and make that our current period + mCurPeriod = (mCurPeriod + num_to_copy - 1) % mRecordingPeriods.size(); + mNumPeriods = llmin(mRecordingPeriods.size(), mNumPeriods + num_to_copy - 1); + } + + // end with fresh period, otherwise next appendPeriodicRecording() will merge the first + // recording period with the last one appended here + nextPeriod(); + getCurRecording().setPlayState(getPlayState()); +} + +LLUnit<F64, LLUnits::Seconds> PeriodicRecording::getDuration() const +{ + LLUnit<F64, LLUnits::Seconds> duration; + size_t num_periods = mRecordingPeriods.size(); + for (size_t i = 1; i <= num_periods; i++) + { + size_t index = (mCurPeriod + num_periods - i) % num_periods; + duration += mRecordingPeriods[index].getDuration(); + } + return duration; +} + + +LLTrace::Recording PeriodicRecording::snapshotCurRecording() const +{ + Recording recording_copy(getCurRecording()); + recording_copy.stop(); + return recording_copy; +} + + +Recording& PeriodicRecording::getLastRecording() +{ + return getPrevRecording(1); +} + +const Recording& PeriodicRecording::getLastRecording() const +{ + return getPrevRecording(1); +} + +Recording& PeriodicRecording::getCurRecording() +{ + return mRecordingPeriods[mCurPeriod]; +} + +const Recording& PeriodicRecording::getCurRecording() const +{ + return mRecordingPeriods[mCurPeriod]; +} + +Recording& PeriodicRecording::getPrevRecording( U32 offset ) +{ + U32 num_periods = mRecordingPeriods.size(); + offset = llclamp(offset, 0u, num_periods - 1); + return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; +} + +const Recording& PeriodicRecording::getPrevRecording( U32 offset ) const +{ + U32 num_periods = mRecordingPeriods.size(); + offset = llclamp(offset, 0u, num_periods - 1); + return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; +} + +void PeriodicRecording::handleStart() +{ + getCurRecording().start(); +} + +void PeriodicRecording::handleStop() +{ + getCurRecording().pause(); +} + +void PeriodicRecording::handleReset() +{ + if (mAutoResize) + { + mRecordingPeriods.clear(); + mRecordingPeriods.push_back(Recording()); + } + else + { + for (std::vector<Recording>::iterator it = mRecordingPeriods.begin(), end_it = mRecordingPeriods.end(); + it != end_it; + ++it) + { + it->reset(); + } + } + mCurPeriod = 0; + getCurRecording().setPlayState(getPlayState()); +} + +void PeriodicRecording::handleSplitTo(PeriodicRecording& other) +{ + getCurRecording().splitTo(other.getCurRecording()); +} + + +F64 PeriodicRecording::getPeriodMean( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 mean = 0; + if (num_periods <= 0) { return mean; } + + S32 total_sample_count = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + S32 period_sample_count = mRecordingPeriods[index].getSampleCount(stat); + mean += mRecordingPeriods[index].getMean(stat) * period_sample_count; + total_sample_count += period_sample_count; + } + } + + if (total_sample_count) + { + mean = mean / total_sample_count; + } + return mean; +} + +F64 PeriodicRecording::getPeriodMin( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat)); + } + return min_val; +} + +F64 PeriodicRecording::getPeriodMax( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat)); + } + return max_val; +} + +F64 PeriodicRecording::getPeriodMin( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat)); + } + return min_val; +} + +F64 PeriodicRecording::getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat)); + } + return max_val; +} + + +F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ ) +{ + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + LLUnit<F64, LLUnits::Seconds> total_duration = 0.f; + + F64 mean = 0; + if (num_periods <= 0) { return mean; } + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + LLUnit<F64, LLUnits::Seconds> recording_duration = mRecordingPeriods[index].getDuration(); + mean += mRecordingPeriods[index].getMean(stat) * recording_duration.value(); + total_duration += recording_duration; + } + } + + if (total_duration.value()) + { + mean = mean / total_duration; + } + return mean; +} + + + +/////////////////////////////////////////////////////////////////////// +// ExtendableRecording +/////////////////////////////////////////////////////////////////////// + +void ExtendableRecording::extend() +{ + // stop recording to get latest data + mPotentialRecording.update(); + // push the data back to accepted recording + mAcceptedRecording.appendRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); +} + +void ExtendableRecording::handleStart() +{ + mPotentialRecording.start(); +} + +void ExtendableRecording::handleStop() +{ + mPotentialRecording.pause(); +} + +void ExtendableRecording::handleReset() +{ + mAcceptedRecording.reset(); + mPotentialRecording.reset(); +} + +void ExtendableRecording::handleSplitTo(ExtendableRecording& other) +{ + mPotentialRecording.splitTo(other.mPotentialRecording); +} + + +/////////////////////////////////////////////////////////////////////// +// ExtendablePeriodicRecording +/////////////////////////////////////////////////////////////////////// + + +ExtendablePeriodicRecording::ExtendablePeriodicRecording() +: mAcceptedRecording(0), + mPotentialRecording(0) +{} + +void ExtendablePeriodicRecording::extend() +{ + // push the data back to accepted recording + mAcceptedRecording.appendPeriodicRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); +} + + +void ExtendablePeriodicRecording::handleStart() +{ + mPotentialRecording.start(); +} + +void ExtendablePeriodicRecording::handleStop() +{ + mPotentialRecording.pause(); +} + +void ExtendablePeriodicRecording::handleReset() +{ + mAcceptedRecording.reset(); + mPotentialRecording.reset(); +} + +void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other) +{ + mPotentialRecording.splitTo(other.mPotentialRecording); +} + + +PeriodicRecording& get_frame_recording() +{ + static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(1000, PeriodicRecording::STARTED)); + return *sRecording; +} + +} + +void LLStopWatchControlsMixinCommon::start() +{ + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + break; + case PAUSED: + handleStart(); + break; + case STARTED: + handleReset(); + break; + default: + llassert(false); + break; + } + mPlayState = STARTED; +} + +void LLStopWatchControlsMixinCommon::stop() +{ + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + break; + case STARTED: + handleStop(); + break; + default: + llassert(false); + break; + } + mPlayState = STOPPED; +} + +void LLStopWatchControlsMixinCommon::pause() +{ + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + break; + case STARTED: + handleStop(); + break; + default: + llassert(false); + break; + } + mPlayState = PAUSED; +} + +void LLStopWatchControlsMixinCommon::resume() +{ + switch (mPlayState) + { + case STOPPED: + handleStart(); + break; + case PAUSED: + handleStart(); + break; + case STARTED: + break; + default: + llassert(false); + break; + } + mPlayState = STARTED; +} + +void LLStopWatchControlsMixinCommon::restart() +{ + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + break; + case PAUSED: + handleReset(); + handleStart(); + break; + case STARTED: + handleReset(); + break; + default: + llassert(false); + break; + } + mPlayState = STARTED; +} + +void LLStopWatchControlsMixinCommon::reset() +{ + handleReset(); +} + +void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state ) +{ + switch(state) + { + case STOPPED: + stop(); + break; + case PAUSED: + pause(); + break; + case STARTED: + start(); + break; + default: + llassert(false); + break; + } + + mPlayState = state; +} diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h new file mode 100644 index 0000000000..b839e85de0 --- /dev/null +++ b/indra/llcommon/lltracerecording.h @@ -0,0 +1,531 @@ +/** + * @file lltracerecording.h + * @brief Sampling object for collecting runtime statistics originating from lltrace. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRACERECORDING_H +#define LL_LLTRACERECORDING_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "llpointer.h" +#include "lltimer.h" +#include "lltrace.h" + +class LLStopWatchControlsMixinCommon +{ +public: + virtual ~LLStopWatchControlsMixinCommon() {} + + enum EPlayState + { + STOPPED, + PAUSED, + STARTED + }; + + void start(); + void stop(); + void pause(); + void resume(); + void restart(); + void reset(); + + bool isStarted() const { return mPlayState == STARTED; } + bool isPaused() const { return mPlayState == PAUSED; } + bool isStopped() const { return mPlayState == STOPPED; } + EPlayState getPlayState() const { return mPlayState; } + // force play state to specific value by calling appropriate handle* methods + void setPlayState(EPlayState state); + +protected: + LLStopWatchControlsMixinCommon() + : mPlayState(STOPPED) + {} + +private: + // trigger active behavior (without reset) + virtual void handleStart() = 0; + // stop active behavior + virtual void handleStop() = 0; + // clear accumulated state, can be called while started + virtual void handleReset() = 0; + + EPlayState mPlayState; +}; + +template<typename DERIVED> +class LLStopWatchControlsMixin +: public LLStopWatchControlsMixinCommon +{ +public: + typedef LLStopWatchControlsMixin<DERIVED> self_t; + virtual void splitTo(DERIVED& other) + { + EPlayState play_state = getPlayState(); + stop(); + other.reset(); + + handleSplitTo(other); + + other.setPlayState(play_state); + } + + virtual void splitFrom(DERIVED& other) + { + static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this)); + } +private: + // atomically stop this object while starting the other + // no data can be missed in between stop and start + virtual void handleSplitTo(DERIVED& other) {}; + +}; + +namespace LLTrace +{ + struct RecordingBuffers : public LLRefCount + { + RecordingBuffers(); + + void handOffTo(RecordingBuffers& other); + void makePrimary(); + bool isPrimary() const; + + void append(const RecordingBuffers& other); + void merge(const RecordingBuffers& other); + void reset(RecordingBuffers* other = NULL); + void flush(); + + AccumulatorBuffer<CountAccumulator> mCounts; + AccumulatorBuffer<SampleAccumulator> mSamples; + AccumulatorBuffer<EventAccumulator> mEvents; + AccumulatorBuffer<TimeBlockAccumulator> mStackTimers; + AccumulatorBuffer<MemStatAccumulator> mMemStats; + }; + + class Recording + : public LLStopWatchControlsMixin<Recording> + { + public: + Recording(); + + Recording(const Recording& other); + ~Recording(); + + Recording& operator = (const Recording& other); + + // accumulate data from subsequent, non-overlapping recording + void appendRecording(const Recording& other); + + // gather data from recording, ignoring time relationship (for example, pulling data from slave threads) + void mergeRecording(const Recording& other); + + // grab latest recorded data + void update(); + + // ensure that buffers are exclusively owned by this recording + void makeUnique() { mBuffers.makeUnique(); } + + // Timer accessors + LLUnit<F64, LLUnits::Seconds> getSum(const TraceType<TimeBlockAccumulator>& stat); + LLUnit<F64, LLUnits::Seconds> getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat); + U32 getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat); + + LLUnit<F64, LLUnits::Seconds> getPerSec(const TraceType<TimeBlockAccumulator>& stat); + LLUnit<F64, LLUnits::Seconds> getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat); + F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat); + + // Memory accessors + LLUnit<F64, LLUnits::Bytes> getMin(const TraceType<MemStatAccumulator>& stat); + LLUnit<F64, LLUnits::Bytes> getMean(const TraceType<MemStatAccumulator>& stat); + LLUnit<F64, LLUnits::Bytes> getMax(const TraceType<MemStatAccumulator>& stat); + LLUnit<F64, LLUnits::Bytes> getStandardDeviation(const TraceType<MemStatAccumulator>& stat); + LLUnit<F64, LLUnits::Bytes> getLastValue(const TraceType<MemStatAccumulator>& stat); + + LLUnit<F64, LLUnits::Bytes> getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); + LLUnit<F64, LLUnits::Bytes> getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); + LLUnit<F64, LLUnits::Bytes> getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); + LLUnit<F64, LLUnits::Bytes> getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); + LLUnit<F64, LLUnits::Bytes> getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat); + + U32 getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat); + U32 getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat); + + // CountStatHandle accessors + F64 getSum(const TraceType<CountAccumulator>& stat); + template <typename T> + T getSum(const CountStatHandle<T>& stat) + { + return (T)getSum(static_cast<const TraceType<CountAccumulator>&> (stat)); + } + + F64 getPerSec(const TraceType<CountAccumulator>& stat); + template <typename T> + T getPerSec(const CountStatHandle<T>& stat) + { + return (T)getPerSec(static_cast<const TraceType<CountAccumulator>&> (stat)); + } + + U32 getSampleCount(const TraceType<CountAccumulator>& stat); + + + // SampleStatHandle accessors + F64 getMin(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getMin(const SampleStatHandle<T>& stat) + { + return (T)getMin(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getMean(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getMean(SampleStatHandle<T>& stat) + { + return (T)getMean(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getMax(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getMax(const SampleStatHandle<T>& stat) + { + return (T)getMax(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getStandardDeviation(const SampleStatHandle<T>& stat) + { + return (T)getStandardDeviation(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + F64 getLastValue(const TraceType<SampleAccumulator>& stat); + template <typename T> + T getLastValue(const SampleStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const TraceType<SampleAccumulator>&> (stat)); + } + + U32 getSampleCount(const TraceType<SampleAccumulator>& stat); + + // EventStatHandle accessors + F64 getSum(const TraceType<EventAccumulator>& stat); + template <typename T> + T getSum(const EventStatHandle<T>& stat) + { + return (T)getSum(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getMin(const TraceType<EventAccumulator>& stat); + template <typename T> + T getMin(const EventStatHandle<T>& stat) + { + return (T)getMin(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getMax(const TraceType<EventAccumulator>& stat); + template <typename T> + T getMax(const EventStatHandle<T>& stat) + { + return (T)getMax(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getMean(const TraceType<EventAccumulator>& stat); + template <typename T> + T getMean(EventStatHandle<T>& stat) + { + return (T)getMean(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const TraceType<EventAccumulator>& stat); + template <typename T> + T getStandardDeviation(const EventStatHandle<T>& stat) + { + return (T)getStandardDeviation(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + F64 getLastValue(const TraceType<EventAccumulator>& stat); + template <typename T> + T getLastValue(const EventStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const TraceType<EventAccumulator>&> (stat)); + } + + U32 getSampleCount(const TraceType<EventAccumulator>& stat); + + LLUnit<F64, LLUnits::Seconds> getDuration() const { return mElapsedSeconds; } + + protected: + friend class ThreadRecorder; + + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(Recording& other); + + // returns data for current thread + class ThreadRecorder* getThreadRecorder(); + + LLTimer mSamplingTimer; + LLUnit<F64, LLUnits::Seconds> mElapsedSeconds; + LLCopyOnWritePointer<RecordingBuffers> mBuffers; + }; + + class LL_COMMON_API PeriodicRecording + : public LLStopWatchControlsMixin<PeriodicRecording> + { + public: + PeriodicRecording(U32 num_periods, EPlayState state = STOPPED); + + void nextPeriod(); + size_t getNumRecordedPeriods() { return mNumPeriods; } + + LLUnit<F64, LLUnits::Seconds> getDuration() const; + + void appendPeriodicRecording(PeriodicRecording& other); + void appendRecording(Recording& recording); + Recording& getLastRecording(); + const Recording& getLastRecording() const; + Recording& getCurRecording(); + const Recording& getCurRecording() const; + Recording& getPrevRecording(U32 offset); + const Recording& getPrevRecording(U32 offset) const; + Recording snapshotCurRecording() const; + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMin(const TraceType<T>& stat, size_t num_periods = U32_MAX) + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename T::value_t min_val = std::numeric_limits<typename T::value_t>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getSum(stat)); + } + return min_val; + } + + F64 getPeriodMin(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX); + template<typename T> + T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX) + { + return T(getPeriodMin(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMin(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX); + template<typename T> + T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX) + { + return T(getPeriodMin(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods)); + } + + template <typename T> + F64 getPeriodMinPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX) + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + min_val = llmin(min_val, mRecordingPeriods[index].getPerSec(stat)); + } + return min_val; + } + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMax(const TraceType<T>& stat, size_t num_periods = U32_MAX) + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename T::value_t max_val = std::numeric_limits<typename T::value_t>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getSum(stat)); + } + return max_val; + } + + F64 getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX); + template<typename T> + T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX) + { + return T(getPeriodMax(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMax(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX); + template<typename T> + T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX) + { + return T(getPeriodMax(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods)); + } + + template <typename T> + F64 getPeriodMaxPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX) + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + max_val = llmax(max_val, mRecordingPeriods[index].getPerSec(stat)); + } + return max_val; + } + + // catch all for stats that have a defined sum + template <typename T> + typename T::mean_t getPeriodMean(const TraceType<T >& stat, size_t num_periods = U32_MAX) + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename T::mean_t mean = 0; + if (num_periods <= 0) { return mean; } + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + mean += mRecordingPeriods[index].getSum(stat); + } + } + mean = mean / num_periods; + return mean; + } + + F64 getPeriodMean(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX); + template<typename T> + T getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX) + { + return T(getPeriodMean(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMean(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX); + template<typename T> + T getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX) + { + return T(getPeriodMean(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods)); + } + + template <typename T> + typename T::mean_t getPeriodMeanPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX) + { + size_t total_periods = mRecordingPeriods.size(); + num_periods = llmin(num_periods, isStarted() ? total_periods - 1 : total_periods); + + typename T::mean_t mean = 0; + if (num_periods <= 0) { return mean; } + + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + total_periods - i) % total_periods; + if (mRecordingPeriods[index].getDuration() > 0.f) + { + mean += mRecordingPeriods[index].getPerSec(stat); + } + } + mean = mean / num_periods; + return mean; + } + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(PeriodicRecording& other); + + private: + std::vector<Recording> mRecordingPeriods; + const bool mAutoResize; + size_t mCurPeriod; + size_t mNumPeriods; + }; + + PeriodicRecording& get_frame_recording(); + + class ExtendableRecording + : public LLStopWatchControlsMixin<ExtendableRecording> + { + public: + void extend(); + + Recording& getAcceptedRecording() { return mAcceptedRecording; } + const Recording& getAcceptedRecording() const {return mAcceptedRecording;} + + Recording& getPotentialRecording() { return mPotentialRecording; } + const Recording& getPotentialRecording() const { return mPotentialRecording;} + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendableRecording& other); + + private: + Recording mAcceptedRecording; + Recording mPotentialRecording; + }; + + class ExtendablePeriodicRecording + : public LLStopWatchControlsMixin<ExtendablePeriodicRecording> + { + public: + ExtendablePeriodicRecording(); + void extend(); + + PeriodicRecording& getAcceptedRecording() { return mAcceptedRecording; } + const PeriodicRecording& getAcceptedRecording() const {return mAcceptedRecording;} + + PeriodicRecording& getPotentialRecording() { return mPotentialRecording; } + const PeriodicRecording& getPotentialRecording() const {return mPotentialRecording;} + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other); + + private: + PeriodicRecording mAcceptedRecording; + PeriodicRecording mPotentialRecording; + }; +} + +#endif // LL_LLTRACERECORDING_H diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp new file mode 100644 index 0000000000..54006f4e5b --- /dev/null +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -0,0 +1,292 @@ +/** + * @file lltracethreadrecorder.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltracethreadrecorder.h" +#include "llfasttimer.h" + +namespace LLTrace +{ + + +/////////////////////////////////////////////////////////////////////// +// ThreadRecorder +/////////////////////////////////////////////////////////////////////// + +ThreadRecorder::ThreadRecorder() +{ + //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies + set_thread_recorder(this); + TimeBlock& root_time_block = TimeBlock::getRootTimeBlock(); + + ThreadTimerStack* timer_stack = ThreadTimerStack::getInstance(); + timer_stack->mTimeBlock = &root_time_block; + timer_stack->mActiveTimer = NULL; + + mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size(); + mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; + + mThreadRecording.start(); + + // initialize time block parent pointers + for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(); + it != end_it; + ++it) + { + TimeBlock& time_block = *it; + TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()]; + tree_node.mBlock = &time_block; + tree_node.mParent = &root_time_block; + + it->getPrimaryAccumulator()->mParent = &root_time_block; + } + + mRootTimer = new BlockTimer(root_time_block); + timer_stack->mActiveTimer = mRootTimer; + + TimeBlock::getRootTimeBlock().getPrimaryAccumulator()->mActiveCount = 1; +} + +ThreadRecorder::~ThreadRecorder() +{ + delete mRootTimer; + + if (!mActiveRecordings.empty()) + { + std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer()); + mActiveRecordings.clear(); + } + + set_thread_recorder(NULL); + delete[] mTimeBlockTreeNodes; +} + +TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index) +{ + if (0 <= index && index < mNumTimeBlockTreeNodes) + { + return &mTimeBlockTreeNodes[index]; + } + return NULL; +} + + +void ThreadRecorder::activate( Recording* recording ) +{ + ActiveRecording* active_recording = new ActiveRecording(recording); + if (!mActiveRecordings.empty()) + { + mActiveRecordings.back()->mPartialRecording.handOffTo(active_recording->mPartialRecording); + } + mActiveRecordings.push_back(active_recording); + + mActiveRecordings.back()->mPartialRecording.makePrimary(); +} + +ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( Recording* recording ) +{ + if (mActiveRecordings.empty()) return mActiveRecordings.rend(); + + mActiveRecordings.back()->mPartialRecording.flush(); + TimeBlock::updateTimes(); + + active_recording_list_t::reverse_iterator it, end_it; + for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); + it != end_it; + ++it) + { + ActiveRecording* cur_recording = *it; + + active_recording_list_t::reverse_iterator next_it = it; + ++next_it; + + // if we have another recording further down in the stack... + if (next_it != mActiveRecordings.rend()) + { + // ...push our gathered data down to it + (*next_it)->mPartialRecording.append(cur_recording->mPartialRecording); + } + + // copy accumulated measurements into result buffer and clear accumulator (mPartialRecording) + cur_recording->movePartialToTarget(); + + if (cur_recording->mTargetRecording == recording) + { + // found the recording, so return it + break; + } + } + + if (it == end_it) + { + llwarns << "Recording not active on this thread" << llendl; + } + + return it; +} + +void ThreadRecorder::deactivate( Recording* recording ) +{ + active_recording_list_t::reverse_iterator it = bringUpToDate(recording); + if (it != mActiveRecordings.rend()) + { + // and if we've found the recording we wanted to update + active_recording_list_t::reverse_iterator next_it = it; + ++next_it; + if (next_it != mActiveRecordings.rend()) + { + (*next_it)->mPartialRecording.makePrimary(); + } + + active_recording_list_t::iterator recording_to_remove = (++it).base(); + llassert((*recording_to_remove)->mTargetRecording == recording); + delete *recording_to_remove; + mActiveRecordings.erase(recording_to_remove); + } +} + +ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target ) +: mTargetRecording(target) +{ +} + +void ThreadRecorder::ActiveRecording::movePartialToTarget() +{ + mTargetRecording->mBuffers.write()->append(mPartialRecording); + // reset based on self to keep history + mPartialRecording.reset(&mPartialRecording); +} + + +/////////////////////////////////////////////////////////////////////// +// SlaveThreadRecorder +/////////////////////////////////////////////////////////////////////// + +SlaveThreadRecorder::SlaveThreadRecorder(MasterThreadRecorder& master) +: mMasterRecorder(master) +{ + mMasterRecorder.addSlaveThread(this); +} + +SlaveThreadRecorder::~SlaveThreadRecorder() +{ + mMasterRecorder.removeSlaveThread(this); +} + +void SlaveThreadRecorder::pushToMaster() +{ + mThreadRecording.stop(); + { + LLMutexLock(mMasterRecorder.getSlaveListMutex()); + mSharedData.appendFrom(mThreadRecording); + } + mThreadRecording.start(); +} + +void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source ) +{ + LLMutexLock lock(&mRecordingMutex); + appendRecording(source); +} + +void SlaveThreadRecorder::SharedData::appendTo( Recording& sink ) +{ + LLMutexLock lock(&mRecordingMutex); + sink.appendRecording(*this); +} + +void SlaveThreadRecorder::SharedData::mergeFrom( const RecordingBuffers& source ) +{ + LLMutexLock lock(&mRecordingMutex); + mBuffers.write()->merge(source); +} + +void SlaveThreadRecorder::SharedData::mergeTo( RecordingBuffers& sink ) +{ + LLMutexLock lock(&mRecordingMutex); + sink.merge(*mBuffers); +} + +void SlaveThreadRecorder::SharedData::reset() +{ + LLMutexLock lock(&mRecordingMutex); + Recording::reset(); +} + + +/////////////////////////////////////////////////////////////////////// +// MasterThreadRecorder +/////////////////////////////////////////////////////////////////////// + +static LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data"); +void MasterThreadRecorder::pullFromSlaveThreads() +{ + LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES); + if (mActiveRecordings.empty()) return; + + LLMutexLock lock(&mSlaveListMutex); + + RecordingBuffers& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; + for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); + it != end_it; + ++it) + { + // ignore block timing info for now + (*it)->mSharedData.mergeTo(target_recording_buffers); + (*it)->mSharedData.reset(); + } +} + +void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child ) +{ + LLMutexLock lock(&mSlaveListMutex); + + mSlaveThreadRecorders.push_back(child); +} + +void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child ) +{ + LLMutexLock lock(&mSlaveListMutex); + + for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end(); + it != end_it; + ++it) + { + if ((*it) == child) + { + mSlaveThreadRecorders.erase(it); + break; + } + } +} + +void MasterThreadRecorder::pushToMaster() +{} + +MasterThreadRecorder::MasterThreadRecorder() +{} + +} diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h new file mode 100644 index 0000000000..bf3701304f --- /dev/null +++ b/indra/llcommon/lltracethreadrecorder.h @@ -0,0 +1,126 @@ +/** + * @file lltrace.h + * @brief Runtime statistics accumulation. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRACETHREADRECORDER_H +#define LL_LLTRACETHREADRECORDER_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "llmutex.h" +#include "lltracerecording.h" + +namespace LLTrace +{ + class LL_COMMON_API ThreadRecorder + { + protected: + struct ActiveRecording; + typedef std::vector<ActiveRecording*> active_recording_list_t; + public: + ThreadRecorder(); + + virtual ~ThreadRecorder(); + + void activate(Recording* recording); + void deactivate(Recording* recording); + active_recording_list_t::reverse_iterator bringUpToDate(Recording* recording); + + virtual void pushToMaster() = 0; + + TimeBlockTreeNode* getTimeBlockTreeNode(S32 index); + + protected: + struct ActiveRecording + { + ActiveRecording(Recording* target); + + Recording* mTargetRecording; + RecordingBuffers mPartialRecording; + + void movePartialToTarget(); + }; + Recording mThreadRecording; + + active_recording_list_t mActiveRecordings; + + class BlockTimer* mRootTimer; + TimeBlockTreeNode* mTimeBlockTreeNodes; + size_t mNumTimeBlockTreeNodes; + }; + + class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder + { + public: + MasterThreadRecorder(); + + void addSlaveThread(class SlaveThreadRecorder* child); + void removeSlaveThread(class SlaveThreadRecorder* child); + + /*virtual */ void pushToMaster(); + + // call this periodically to gather stats data from slave threads + void pullFromSlaveThreads(); + + LLMutex* getSlaveListMutex() { return &mSlaveListMutex; } + + + private: + + typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t; + + slave_thread_recorder_list_t mSlaveThreadRecorders; // list of slave thread recorders associated with this master + LLMutex mSlaveListMutex; // protects access to slave list + }; + + class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder + { + public: + SlaveThreadRecorder(MasterThreadRecorder& master); + ~SlaveThreadRecorder(); + + // call this periodically to gather stats data for master thread to consume + /*virtual*/ void pushToMaster(); + + MasterThreadRecorder* mMaster; + + class SharedData : public Recording + { + public: + void appendFrom(const Recording& source); + void appendTo(Recording& sink); + void mergeFrom(const RecordingBuffers& source); + void mergeTo(RecordingBuffers& sink); + void reset(); + private: + LLMutex mRecordingMutex; + }; + SharedData mSharedData; + MasterThreadRecorder& mMasterRecorder; + }; +} + +#endif // LL_LLTRACETHREADRECORDER_H diff --git a/indra/llcommon/lltypeinfolookup.h b/indra/llcommon/lltypeinfolookup.h deleted file mode 100755 index 0b6862444e..0000000000 --- a/indra/llcommon/lltypeinfolookup.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file lltypeinfolookup.h - * @author Nat Goodspeed - * @date 2012-04-08 - * @brief Template data structure like std::map<std::type_info*, T> - * - * $LicenseInfo:firstyear=2012&license=viewerlgpl$ - * Copyright (c) 2012, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLTYPEINFOLOOKUP_H) -#define LL_LLTYPEINFOLOOKUP_H - -#include <boost/unordered_map.hpp> -#include <boost/functional/hash.hpp> -#include <boost/optional.hpp> -#include <functional> // std::binary_function -#include <typeinfo> - -/** - * The following helper classes are based on the Boost.Unordered documentation: - * http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html - */ - -/** - * Compute hash for a string passed as const char* - */ -struct const_char_star_hash: public std::unary_function<const char*, std::size_t> -{ - std::size_t operator()(const char* str) const - { - std::size_t seed = 0; - for ( ; *str; ++str) - { - boost::hash_combine(seed, *str); - } - return seed; - } -}; - -/** - * Compute equality for strings passed as const char* - * - * I (nat) suspect that this is where the default behavior breaks for the - * const char* values returned from std::type_info::name(). If you compare the - * two const char* pointer values, as a naive, unspecialized implementation - * will surely do, they'll compare unequal. - */ -struct const_char_star_equal: public std::binary_function<const char*, const char*, bool> -{ - bool operator()(const char* lhs, const char* rhs) const - { - return strcmp(lhs, rhs) == 0; - } -}; - -/** - * LLTypeInfoLookup is specifically designed for use cases for which you might - * consider std::map<std::type_info*, VALUE>. We have several such data - * structures in the viewer. The trouble with them is that at least on Linux, - * you can't rely on always getting the same std::type_info* for a given type: - * different load modules will produce different std::type_info*. - * LLTypeInfoLookup contains a workaround to address this issue. - * - * The API deliberately diverges from std::map in several respects: - * * It avoids iterators, not only begin()/end() but also as return values - * from insert() and find(). This bypasses transform_iterator overhead. - * * Since we literally use compile-time types as keys, the essential insert() - * and find() methods accept the key type as a @em template parameter, - * accepting and returning value_type as a normal runtime value. This is to - * permit future optimization (e.g. compile-time type hashing) without - * changing the API. - */ -template <typename VALUE> -class LLTypeInfoLookup -{ - // Use this for our underlying implementation: lookup by - // std::type_info::name() string. This is one of the rare cases in which I - // dare use const char* directly, rather than std::string, because I'm - // sure that every value returned by std::type_info::name() is static. - // HOWEVER, specify our own hash + equality functors: naively comparing - // distinct const char* values won't work. - typedef boost::unordered_map<const char*, VALUE, - const_char_star_hash, const_char_star_equal> impl_map_type; - -public: - typedef VALUE value_type; - - LLTypeInfoLookup() {} - - bool empty() const { return mMap.empty(); } - std::size_t size() const { return mMap.size(); } - - template <typename KEY> - bool insert(const value_type& value) - { - // Obtain and store the std::type_info::name() string as the key. - // Return just the bool from std::map::insert()'s return pair. - return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second; - } - - template <typename KEY> - boost::optional<value_type> find() const - { - // Use the std::type_info::name() string as the key. - typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name()); - if (found == mMap.end()) - return boost::optional<value_type>(); - return found->second; - } - -private: - impl_map_type mMap; -}; - -#endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */ diff --git a/indra/llcommon/llunit.h b/indra/llcommon/llunit.h new file mode 100644 index 0000000000..2402cdbb95 --- /dev/null +++ b/indra/llcommon/llunit.h @@ -0,0 +1,563 @@ +/** + * @file llunit.h + * @brief Unit conversion classes + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLUNIT_H +#define LL_LLUNIT_H + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llerrorlegacy.h" +#include <boost/type_traits/is_same.hpp> + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +struct LLUnit +{ + typedef LLUnit<STORAGE_TYPE, UNIT_TYPE> self_t; + typedef STORAGE_TYPE storage_t; + + // value initialization + LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + // unit initialization and conversion + template<typename OTHER_STORAGE, typename OTHER_UNIT> + LLUnit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other) + : mValue(convert(other).mValue) + {} + + bool operator == (const self_t& other) + { + return mValue = other.mValue; + } + + // value assignment + self_t& operator = (storage_t value) + { + mValue = value; + return *this; + } + + // unit assignment + template<typename OTHER_STORAGE, typename OTHER_UNIT> + self_t& operator = (LLUnit<OTHER_STORAGE, OTHER_UNIT> other) + { + mValue = convert(other).mValue; + return *this; + } + + storage_t value() const + { + return mValue; + } + + template<typename NEW_UNIT_TYPE> + STORAGE_TYPE getAs() + { + return LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(*this).value(); + } + + template<typename NEW_UNIT_TYPE> + STORAGE_TYPE setAs(STORAGE_TYPE val) + { + *this = LLUnit<STORAGE_TYPE, NEW_UNIT_TYPE>(val); + } + + void operator += (storage_t value) + { + mValue += value; + } + + template<typename OTHER_STORAGE, typename OTHER_UNIT> + void operator += (LLUnit<OTHER_STORAGE, OTHER_UNIT> other) + { + mValue += convert(other).mValue; + } + + void operator -= (storage_t value) + { + mValue -= value; + } + + template<typename OTHER_STORAGE, typename OTHER_UNIT> + void operator -= (LLUnit<OTHER_STORAGE, OTHER_UNIT> other) + { + mValue -= convert(other).mValue; + } + + void operator *= (storage_t multiplicand) + { + mValue *= multiplicand; + } + + template<typename OTHER_UNIT, typename OTHER_STORAGE> + void operator *= (LLUnit<OTHER_STORAGE, OTHER_UNIT> multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(OTHER_UNIT, "Multiplication of unit types not supported."); + } + + void operator /= (storage_t divisor) + { + mValue /= divisor; + } + + template<typename OTHER_UNIT, typename OTHER_STORAGE> + void operator /= (LLUnit<OTHER_STORAGE, OTHER_UNIT> divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(OTHER_UNIT, "Illegal in-place division of unit types."); + } + + template<typename SOURCE_STORAGE, typename SOURCE_UNITS> + static self_t convert(LLUnit<SOURCE_STORAGE, SOURCE_UNITS> v) + { + self_t result; + ll_convert_units(v, result); + return result; + } + +protected: + storage_t mValue; +}; + +template<typename STORAGE_TYPE, typename UNIT_TYPE> +struct LLUnitImplicit : public LLUnit<STORAGE_TYPE, UNIT_TYPE> +{ + typedef LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> self_t; + typedef typename LLUnit<STORAGE_TYPE, UNIT_TYPE>::storage_t storage_t; + typedef LLUnit<STORAGE_TYPE, UNIT_TYPE> base_t; + + LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template<typename OTHER_STORAGE, typename OTHER_UNIT> + LLUnitImplicit(LLUnit<OTHER_STORAGE, OTHER_UNIT> other) + : base_t(convert(other)) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD scalar (F32, S32, etc) + // this allows for interoperability with legacy code + operator storage_t() const + { + return base_t::value(); + } +}; + + +template<typename S1, typename T1, typename S2, typename T2> +LL_FORCE_INLINE void ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out, ...) +{ + typedef boost::integral_constant<bool, + boost::is_same<T1, T2>::value + || !boost::is_same<T1, typename T1::base_unit_t>::value + || !boost::is_same<T2, typename T2::base_unit_t>::value> conversion_valid_t; + LL_STATIC_ASSERT(conversion_valid_t::value, "invalid conversion"); + + if (boost::is_same<T1, typename T1::base_unit_t>::value) + { + if (boost::is_same<T2, typename T2::base_unit_t>::value) + { + // T1 and T2 fully reduced and equal...just copy + out = (S2)in.value(); + } + else + { + // reduce T2 + LLUnit<S2, typename T2::base_unit_t> new_out; + ll_convert_units(in, new_out); + ll_convert_units(new_out, out); + } + } + else + { + // reduce T1 + LLUnit<S1, typename T1::base_unit_t> new_in; + ll_convert_units(in, new_in); + ll_convert_units(new_in, out); + } +} + +// +// operator + +// +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnit<STORAGE_TYPE1, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator + (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) +{ + LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator + (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> result(first); + result += second; + return result; +} + +// +// operator - +// +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator - (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnit<STORAGE_TYPE1, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator - (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) +{ + LLUnit<STORAGE_TYPE, UNIT_TYPE> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator - (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator - (SCALAR_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second) +{ + LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> result(first); + result -= second; + return result; +} + +// +// operator * +// +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator * (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) +{ + return LLUnit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first * second.value())); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator * (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + return LLUnit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first.value() * second)); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnit<STORAGE_TYPE2, UNIT_TYPE2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "Multiplication of unit types results in new unit type - not supported."); + return LLUnit<STORAGE_TYPE1, UNIT_TYPE1>(); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator * (SCALAR_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> second) +{ + return LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>(first * second.value()); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator * (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + return LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>(first.value() * second); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> operator * (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "Multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1>(); +} + +// +// operator / +// +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) +{ + return SCALAR_TYPE(first / second.value()); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnit<STORAGE_TYPE, UNIT_TYPE> operator / (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + return LLUnit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first.value() / second)); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +STORAGE_TYPE1 operator / (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + return STORAGE_TYPE1(first.value() / first.convert(second)); +} + +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> +LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> operator / (LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) +{ + return LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE>((STORAGE_TYPE)(first.value() / second)); +} + +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> +STORAGE_TYPE1 operator / (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) +{ + return STORAGE_TYPE1(first.value() / first.convert(second)); +} + +#define COMPARISON_OPERATORS(op) \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> \ +bool operator op (SCALAR_TYPE first, LLUnit<STORAGE_TYPE, UNIT_TYPE> second) \ +{ \ + return first op second.value(); \ +} \ + \ +template<typename STORAGE_TYPE, typename UNIT_TYPE, typename SCALAR_TYPE> \ +bool operator op (LLUnit<STORAGE_TYPE, UNIT_TYPE> first, SCALAR_TYPE second) \ +{ \ + return first.value() op second; \ +} \ + \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \ +bool operator op (LLUnitImplicit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnitImplicit<STORAGE_TYPE2, UNIT_TYPE2> second) \ +{ \ + return first.value() op first.convert(second); \ +} \ + \ +template<typename STORAGE_TYPE1, typename UNIT_TYPE1, typename STORAGE_TYPE2, typename UNIT_TYPE2> \ + bool operator op (LLUnit<STORAGE_TYPE1, UNIT_TYPE1> first, LLUnit<STORAGE_TYPE2, UNIT_TYPE2> second) \ +{ \ + return first.value() op first.convert(second); \ +} + +COMPARISON_OPERATORS(<) +COMPARISON_OPERATORS(<=) +COMPARISON_OPERATORS(>) +COMPARISON_OPERATORS(>=) +COMPARISON_OPERATORS(==) +COMPARISON_OPERATORS(!=) + + +template<typename T> +struct LLGetUnitLabel +{ + static const char* getUnitLabel() { return ""; } +}; + +template<typename T, typename STORAGE_T> +struct LLGetUnitLabel<LLUnit<STORAGE_T, T> > +{ + static const char* getUnitLabel() { return T::getUnitLabel(); } +}; + +template<typename VALUE_TYPE> +struct LLUnitLinearOps +{ + typedef LLUnitLinearOps<VALUE_TYPE> self_t; + LLUnitLinearOps(VALUE_TYPE val) : mValue (val) {} + + operator VALUE_TYPE() const { return mValue; } + VALUE_TYPE mValue; + + template<typename T> + self_t operator * (T other) + { + return mValue * other; + } + + template<typename T> + self_t operator / (T other) + { + return mValue / other; + } + + template<typename T> + self_t operator + (T other) + { + return mValue + other; + } + + template<typename T> + self_t operator - (T other) + { + return mValue - other; + } +}; + +template<typename VALUE_TYPE> +struct LLUnitInverseLinearOps +{ + typedef LLUnitInverseLinearOps<VALUE_TYPE> self_t; + + LLUnitInverseLinearOps(VALUE_TYPE val) : mValue (val) {} + operator VALUE_TYPE() const { return mValue; } + VALUE_TYPE mValue; + + template<typename T> + self_t operator * (T other) + { + return mValue / other; + } + + template<typename T> + self_t operator / (T other) + { + return mValue * other; + } + + template<typename T> + self_t operator + (T other) + { + return mValue - other; + } + + template<typename T> + self_t operator - (T other) + { + return mValue + other; + } +}; + +#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ +struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }} + +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ +struct unit_name \ +{ \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ +}; \ + \ +template<typename S1, typename S2> \ +void ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out) \ +{ \ + out = (S2)(LLUnitLinearOps<S1>(in.value()) conversion_operation).mValue; \ +} \ + \ +template<typename S1, typename S2> \ +void ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out) \ +{ \ + out = (S2)(LLUnitInverseLinearOps<S1>(in.value()) conversion_operation).mValue; \ +} + +// +// Unit declarations +// + +namespace LLUnits +{ +LL_DECLARE_BASE_UNIT(Bytes, "B"); +LL_DECLARE_DERIVED_UNIT(Kilobytes, "KB", Bytes, * 1000); +LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Kilobytes, * 1000); +LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Megabytes, * 1000); +LL_DECLARE_DERIVED_UNIT(Kibibytes, "KiB", Bytes, * 1024); +LL_DECLARE_DERIVED_UNIT(Mibibytes, "MiB", Kibibytes, * 1024); +LL_DECLARE_DERIVED_UNIT(Gibibytes, "GiB", Mibibytes, * 1024); + +LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, / 8); +LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bytes, * 1000 / 8); +LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, * 1000 / 8); +LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, * 1000 / 8); +LL_DECLARE_DERIVED_UNIT(Kibibits, "Kib", Bytes, * 1024 / 8); +LL_DECLARE_DERIVED_UNIT(Mibibits, "Mib", Kibibits, * 1024 / 8); +LL_DECLARE_DERIVED_UNIT(Gibibits, "Gib", Mibibits, * 1024 / 8); + +LL_DECLARE_BASE_UNIT(Seconds, "s"); +LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, * 60); +LL_DECLARE_DERIVED_UNIT(Hours, "h", Seconds, * 60 * 60); +LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, / 1000); +LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, / 1000); +LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, / 1000); + +LL_DECLARE_BASE_UNIT(Meters, "m"); +LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, * 1000); +LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, / 100); +LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, / 1000); + +LL_DECLARE_BASE_UNIT(Hertz, "Hz"); +LL_DECLARE_DERIVED_UNIT(Kilohertz, "KHz", Hertz, * 1000); +LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Kilohertz, * 1000); +LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Megahertz, * 1000); + +LL_DECLARE_BASE_UNIT(Radians, "rad"); +LL_DECLARE_DERIVED_UNIT(Degrees, "deg", Radians, * 0.01745329251994); + + +} // namespace LLUnits + +#endif // LL_LLUNIT_H diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 0aaa50d231..ba4b670b9a 100755 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -27,9 +27,7 @@ // We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes. #if LL_WINDOWS -#undef WIN32_LEAN_AND_MEAN -#include <winsock2.h> -#include <windows.h> +#include "llwin32headers.h" // ugh, this is ugly. We need to straighten out our linking for this library #pragma comment(lib, "IPHLPAPI.lib") #include <iphlpapi.h> diff --git a/indra/llcommon/lluuidhashmap.h b/indra/llcommon/lluuidhashmap.h deleted file mode 100755 index e294670030..0000000000 --- a/indra/llcommon/lluuidhashmap.h +++ /dev/null @@ -1,583 +0,0 @@ -/** - * @file lluuidhashmap.h - * @brief A uuid based hash map. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLUUIDHASHMAP_H -#define LL_LLUUIDHASHMAP_H - -#include "stdtypes.h" -#include "llerror.h" -#include "lluuid.h" - -// UUID hash map - - /* - LLUUIDHashMap<uuid_pair, 32> foo(test_equals); - LLUUIDHashMapIter<uuid_pair, 32> bar(&foo); - - LLDynamicArray<LLUUID> source_ids; - const S32 COUNT = 100000; - S32 q; - for (q = 0; q < COUNT; q++) - { - llinfos << "Creating" << llendl; - LLUUID id; - id.generate(); - //llinfos << q << ":" << id << llendl; - uuid_pair pair; - pair.mUUID = id; - pair.mValue = q; - foo.set(id, pair); - source_ids.put(id); - //ms_sleep(1); - } - - uuid_pair cur; - llinfos << "Iterating" << llendl; - for (cur = bar.first(); !bar.done(); cur = bar.next()) - { - if (source_ids[cur.mValue] != cur.mUUID) - { - llerrs << "Incorrect value iterated!" << llendl; - } - //llinfos << cur.mValue << ":" << cur.mUUID << llendl; - //ms_sleep(1); - } - - llinfos << "Finding" << llendl; - for (q = 0; q < COUNT; q++) - { - cur = foo.get(source_ids[q]); - if (source_ids[cur.mValue] != cur.mUUID) - { - llerrs << "Incorrect value found!" << llendl; - } - //llinfos << res.mValue << ":" << res.mUUID << llendl; - //ms_sleep(1); - } - - llinfos << "Removing" << llendl; - for (q = 0; q < COUNT/2; q++) - { - if (!foo.remove(source_ids[q])) - { - llerrs << "Remove failed!" << llendl; - } - //ms_sleep(1); - } - - llinfos << "Iterating" << llendl; - for (cur = bar.first(); !bar.done(); cur = bar.next()) - { - if (source_ids[cur.mValue] != cur.mUUID) - { - llerrs << "Incorrect value found!" << llendl; - } - //llinfos << cur.mValue << ":" << cur.mUUID << llendl; - //ms_sleep(1); - } - llinfos << "Done with UUID map test" << llendl; - - return 0; - */ - - -// -// LLUUIDHashNode -// - -template <class DATA, int SIZE> -class LLUUIDHashNode -{ -public: - LLUUIDHashNode(); - -public: - S32 mCount; - U8 mKey[SIZE]; - DATA mData[SIZE]; - LLUUIDHashNode<DATA, SIZE> *mNextNodep; -}; - - -// -// LLUUIDHashNode implementation -// -template <class DATA, int SIZE> -LLUUIDHashNode<DATA, SIZE>::LLUUIDHashNode() -{ - mCount = 0; - mNextNodep = NULL; -} - - -template <class DATA_TYPE, int SIZE> -class LLUUIDHashMap -{ -public: - // basic constructor including sorter - LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data), - const DATA_TYPE &null_data); - ~LLUUIDHashMap(); - - inline DATA_TYPE &get(const LLUUID &uuid); - inline BOOL check(const LLUUID &uuid) const; - inline DATA_TYPE &set(const LLUUID &uuid, const DATA_TYPE &type); - inline BOOL remove(const LLUUID &uuid); - void removeAll(); - - inline S32 getLength() const; // Warning, NOT O(1!) -public: - BOOL (*mEquals)(const LLUUID &uuid, const DATA_TYPE &data); - LLUUIDHashNode<DATA_TYPE, SIZE> mNodes[256]; - - S32 mIterCount; -protected: - DATA_TYPE mNull; -}; - - -// -// LLUUIDHashMap implementation -// - -template <class DATA_TYPE, int SIZE> -LLUUIDHashMap<DATA_TYPE, SIZE>::LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data), - const DATA_TYPE &null_data) -: mEquals(equals), - mIterCount(0), - mNull(null_data) -{ } - -template <class DATA_TYPE, int SIZE> -LLUUIDHashMap<DATA_TYPE, SIZE>::~LLUUIDHashMap() -{ - removeAll(); -} - -template <class DATA_TYPE, int SIZE> -void LLUUIDHashMap<DATA_TYPE, SIZE>::removeAll() -{ - S32 bin; - for (bin = 0; bin < 256; bin++) - { - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - - BOOL first = TRUE; - while (nodep) - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - nodep->mData[i] = mNull; - } - - nodep->mCount = 0; - // Done with all objects in this node, go to the next. - - LLUUIDHashNode<DATA_TYPE, SIZE>* curp = nodep; - nodep = nodep->mNextNodep; - - // Delete the node if it's not the first node - if (first) - { - first = FALSE; - curp->mNextNodep = NULL; - } - else - { - delete curp; - } - } - } -} - -template <class DATA_TYPE, int SIZE> -inline S32 LLUUIDHashMap<DATA_TYPE, SIZE>::getLength() const -{ - S32 count = 0; - S32 bin; - for (bin = 0; bin < 256; bin++) - { - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = (LLUUIDHashNode<DATA_TYPE, SIZE>*) &mNodes[bin]; - while (nodep) - { - count += nodep->mCount; - nodep = nodep->mNextNodep; - } - } - return count; -} - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::get(const LLUUID &uuid) -{ - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]]; - - // Grab the second byte of the UUID, which is the key for the node data - const S32 second_byte = uuid.mData[1]; - while (nodep) - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // The second byte matched, and our equality test passed. - // We found it. - return nodep->mData[i]; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } - return mNull; -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::check(const LLUUID &uuid) const -{ - const LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]]; - - // Grab the second byte of the UUID, which is the key for the node data - const S32 second_byte = uuid.mData[1]; - while (nodep) - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // The second byte matched, and our equality test passed. - // We found it. - return TRUE; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } - - // Didn't find anything - return FALSE; -} - - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::set(const LLUUID &uuid, const DATA_TYPE &data) -{ - // Set is just like a normal find, except that if we find a match - // we replace it with the input value. - // If we don't find a match, we append to the end of the list. - - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]]; - - const S32 second_byte = uuid.mData[1]; - while (1) - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // We found a match for this key, replace the data with - // the incoming data. - nodep->mData[i] = data; - return nodep->mData[i]; - } - } - if (!nodep->mNextNodep) - { - // We've iterated through all of the keys without finding a match - if (i < SIZE) - { - // There's still some space on this node, append - // the key and data to it. - nodep->mKey[i] = second_byte; - nodep->mData[i] = data; - nodep->mCount++; - - return nodep->mData[i]; - } - else - { - // This node is full, append a new node to the end. - nodep->mNextNodep = new LLUUIDHashNode<DATA_TYPE, SIZE>; - nodep->mNextNodep->mKey[0] = second_byte; - nodep->mNextNodep->mData[0] = data; - nodep->mNextNodep->mCount = 1; - - return nodep->mNextNodep->mData[0]; - } - } - - // No match on this node, go to the next - nodep = nodep->mNextNodep; - } -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::remove(const LLUUID &uuid) -{ - if (mIterCount) - { - // We don't allow remove when we're iterating, it's bad karma! - llerrs << "Attempted remove while an outstanding iterator in LLUUIDHashMap!" << llendl; - } - // Remove is the trickiest operation. - // What we want to do is swap the last element of the last - // node if we find the one that we want to remove, but we have - // to deal with deleting the node from the tail if it's empty, but - // NOT if it's the only node left. - - LLUUIDHashNode<DATA_TYPE, SIZE> *nodep = &mNodes[uuid.mData[0]]; - - // Not empty, we need to search through the nodes - const S32 second_byte = uuid.mData[1]; - - // A modification of the standard search algorithm. - while (nodep) - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // We found the node that we want to remove. - // Find the last (and next-to-last) node, and the index of the last - // element. We could conceviably start from the node we're on, - // but that makes it more complicated, this is easier. - - LLUUIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[uuid.mData[0]]; - LLUUIDHashNode<DATA_TYPE, SIZE> *lastp = prevp; - - // Find the last and next-to-last - while (lastp->mNextNodep) - { - prevp = lastp; - lastp = lastp->mNextNodep; - } - - // First, swap in the last to the current location. - nodep->mKey[i] = lastp->mKey[lastp->mCount - 1]; - nodep->mData[i] = lastp->mData[lastp->mCount - 1]; - - // Now, we delete the entry - lastp->mCount--; - lastp->mData[lastp->mCount] = mNull; - - if (!lastp->mCount) - { - // We deleted the last element! - if (lastp != &mNodes[uuid.mData[0]]) - { - // Only blitz the node if it's not the head - // Set the previous node to point to NULL, then - // blitz the empty last node - prevp->mNextNodep = NULL; - delete lastp; - } - } - return TRUE; - } - } - - // Iterate to the next node, we've scanned all the entries in this one. - nodep = nodep->mNextNodep; - } - return FALSE; -} - - -// -// LLUUIDHashMapIter -// - -template <class DATA_TYPE, int SIZE> -class LLUUIDHashMapIter -{ -public: - LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp); - ~LLUUIDHashMapIter(); - - - inline void reset(); - inline void first(); - inline void next(); - inline BOOL done() const; - - DATA_TYPE& operator*() const - { - return mCurHashNodep->mData[mCurHashNodeKey]; - } - DATA_TYPE* operator->() const - { - return &(operator*()); - } - -protected: - LLUUIDHashMap<DATA_TYPE, SIZE> *mHashMapp; - LLUUIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep; - - S32 mCurHashMapNodeNum; - S32 mCurHashNodeKey; - - DATA_TYPE mNull; -}; - - -// -// LLUUIDHashMapIter Implementation -// -template <class DATA_TYPE, int SIZE> -LLUUIDHashMapIter<DATA_TYPE, SIZE>::LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp) -{ - mHashMapp = hash_mapp; - mCurHashNodep = NULL; - mCurHashMapNodeNum = 0; - mCurHashNodeKey = 0; -} - -template <class DATA_TYPE, int SIZE> -LLUUIDHashMapIter<DATA_TYPE, SIZE>::~LLUUIDHashMapIter() -{ - reset(); -} - -template <class DATA_TYPE, int SIZE> -inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::reset() -{ - if (mCurHashNodep) - { - // We're partway through an iteration, we can clean up now - mHashMapp->mIterCount--; - mCurHashNodep = NULL; - } -} - -template <class DATA_TYPE, int SIZE> -inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::first() -{ - // Iterate through until we find the first non-empty node; - S32 i; - for (i = 0; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - if (!mCurHashNodep) - { - // Increment, since it's no longer safe for us to do a remove - mHashMapp->mIterCount++; - } - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // Completely empty! - mCurHashNodep = NULL; - //return mNull; - return; -} - -template <class DATA_TYPE, int SIZE> -inline BOOL LLUUIDHashMapIter<DATA_TYPE, SIZE>::done() const -{ - return mCurHashNodep ? FALSE : TRUE; -} - -template <class DATA_TYPE, int SIZE> -inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::next() -{ - // No current entry, this iterator is done - if (!mCurHashNodep) - { - //return mNull; - return; - } - - // Go to the next element - mCurHashNodeKey++; - if (mCurHashNodeKey < mCurHashNodep->mCount) - { - // We're not done with this node, return the current element - //return mCurHashNodep->mData[mCurHashNodeKey]; - return; - } - - // Done with this node, move to the next - mCurHashNodep = mCurHashNodep->mNextNodep; - if (mCurHashNodep) - { - // Return the first element - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - - // Find the next non-empty node (keyed on the first byte) - mCurHashMapNodeNum++; - - S32 i; - for (i = mCurHashMapNodeNum; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - // We found one that wasn't empty - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // OK, we're done, nothing else to iterate - mCurHashNodep = NULL; - mHashMapp->mIterCount--; // Decrement since we're safe to do removes now - //return mNull; -} - -#endif // LL_LLUUIDHASHMAP_H diff --git a/indra/llcommon/reflective.cpp b/indra/llcommon/llwin32headers.h index 2cc0e7e1f2..cf85067d95 100755..100644 --- a/indra/llcommon/reflective.cpp +++ b/indra/llcommon/llwin32headers.h @@ -1,10 +1,8 @@ /** - * @file reflective.cpp - * @author Babbage - * @date 2006-05-15 - * @brief Implementation of LLReflective. + * @file llwindows.h + * @brief sanitized include of windows header files * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -26,15 +24,19 @@ * $/LicenseInfo$ */ -#include "linden_common.h" - -#include "reflective.h" +#ifndef LL_LLWINDOWS_H +#define LL_LLWINDOWS_H -LLReflective::LLReflective() -{ -} +#ifdef LL_WINDOWS +#ifndef NOMINMAX +#define NOMINMAX +#endif +#undef WIN32_LEAN_AND_MEAN +#include <winsock2.h> +#include <windows.h> +// reset to default, which is lean +#define WIN32_LEAN_AND_MEAN +#undef NOMINMAX +#endif -//virtual -LLReflective::~LLReflective() -{ -} +#endif diff --git a/indra/llcommon/lldarrayptr.h b/indra/llcommon/llwin32headerslean.h index c9a0b204d1..f7e71301a8 100755..100644 --- a/indra/llcommon/lldarrayptr.h +++ b/indra/llcommon/llwin32headerslean.h @@ -1,6 +1,6 @@ /** - * @file lldarrayptr.h - * @brief Wrapped std::vector for backward compatibility. + * @file llwindows.h + * @brief sanitized include of windows header files * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,14 +23,18 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_LLDARRAYPTR_H -#define LL_LLDARRAYPTR_H -#include "lldarray.h" +#ifndef LL_LLWINDOWS_H +#define LL_LLWINDOWS_H -template <class Type, int BlockSize = 32> -class LLDynamicArrayPtr : public LLDynamicArray<Type, BlockSize> -{ -}; +#ifdef LL_WINDOWS +#ifndef NOMINMAX +#define NOMINMAX +#endif +#define WIN32_LEAN_AND_MEAN +#include <winsock2.h> +#include <windows.h> +#undef NOMINMAX +#endif -#endif // LL_LLDARRAYPTR_H +#endif diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index be46394d6e..09776816a8 100755 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -26,10 +26,11 @@ #ifndef LL_LLWORKERTHREAD_H #define LL_LLWORKERTHREAD_H -#include <queue> -#include <string> +#include <list> #include <map> +#include <queue> #include <set> +#include <string> #include "llqueuedthread.h" #include "llapr.h" diff --git a/indra/llcommon/metaclass.cpp b/indra/llcommon/metaclass.cpp deleted file mode 100755 index 5e403511cf..0000000000 --- a/indra/llcommon/metaclass.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file metaclass.cpp - * @author Babbage - * @date 2006-05-15 - * @brief Implementation of LLMetaClass - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "metaclass.h" - -#include "metaproperty.h" -#include "reflective.h" - -LLMetaClass::LLMetaClass() -{ -} - -//virtual -LLMetaClass::~LLMetaClass() -{ -} - -const LLMetaProperty* LLMetaClass::findProperty(const std::string& name) const -{ - PropertyIterator iter = mProperties.find(name); - if(iter == mProperties.end()) - { - return NULL; - } - return (*iter).second; -} - -void LLMetaClass::addProperty(const LLMetaProperty* property) -{ - mProperties.insert(std::make_pair(property->getName(), property)); -} - -U32 LLMetaClass::getPropertyCount() const -{ - return mProperties.size(); -} - -LLMetaClass::PropertyIterator LLMetaClass::beginProperties() const -{ - return mProperties.begin(); -} - -LLMetaClass::PropertyIterator LLMetaClass::endProperties() const -{ - return mProperties.end(); -} - -bool LLMetaClass::isInstance(const LLReflective* object) const -{ - // TODO: Babbage: Search through super classes of objects MetaClass. - const LLMetaClass* object_meta_class = &(object->getMetaClass()); - return (object_meta_class == this); -} - diff --git a/indra/llcommon/metaclass.h b/indra/llcommon/metaclass.h deleted file mode 100755 index 626757d58d..0000000000 --- a/indra/llcommon/metaclass.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file metaclass.h - * @author Babbage - * @date 2006-05-15 - * @brief Reflective meta information describing a class. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METACLASS_H -#define LL_METACLASS_H - -#include <string> -#include <map> - -#include "stdtypes.h" - -class LLReflective; -class LLMetaProperty; -class LLMetaMethod; -class LL_COMMON_API LLMetaClass -{ -public: - - LLMetaClass(); - virtual ~LLMetaClass(); - - // Create instance of this MetaClass. NULL if class is abstract. - // Gives ownership of returned object. - // virtual LLReflective* create() const = 0; - - // Returns named property or NULL. - const LLMetaProperty* findProperty(const std::string& name) const; - - // Add property to metaclass. Takes ownership of given property. - void addProperty(const LLMetaProperty* property); - - typedef std::map<std::string, const LLMetaProperty*>::const_iterator PropertyIterator; - - U32 getPropertyCount() const; - - PropertyIterator beginProperties() const; - PropertyIterator endProperties() const; - - // Returns named property or NULL. - // const LLMetaMethod* findMethod(const std::string& name) const; - - // Add method to metaclass. Takes ownership of given method. - // void addMethod(const LLMetaMethod* method); - - // Find MetaClass by name. NULL if name is unknown. - // static LLMetaClass* findClass(const std::string& name); - - // True if object is instance of this meta class. - bool isInstance(const LLReflective* object) const; - -private: - - typedef std::map<std::string, const LLMetaProperty*> PropertyMap; - PropertyMap mProperties; -}; - -#endif // LL_METACLASS_H diff --git a/indra/llcommon/metaclasst.h b/indra/llcommon/metaclasst.h deleted file mode 100755 index b9a7ae219d..0000000000 --- a/indra/llcommon/metaclasst.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file metaclasst.h - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METACLASST_H -#define LL_METACLASST_H - -#include "metaclass.h" - -template<class TObject> -class LLMetaClassT : public LLMetaClass -{ - public: - - virtual ~LLMetaClassT() {;} - - static const LLMetaClassT& instance() - { - static const LLMetaClassT& instance = buildMetaClass(); - return instance; - } - - private: - - static const LLMetaClassT& buildMetaClass() - { - LLMetaClassT& meta_class = *(new LLMetaClassT()); - reflectProperties(meta_class); - return meta_class; - } - - LLMetaClassT() {;} - - static void reflectProperties(LLMetaClass&) - { - } -}; - -#endif // LL_METACLASST_H diff --git a/indra/llcommon/metaproperty.cpp b/indra/llcommon/metaproperty.cpp deleted file mode 100755 index 98d850bf1e..0000000000 --- a/indra/llcommon/metaproperty.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file metaproperty.cpp - * @author Babbage - * @date 2006-05-15 - * @brief Implementation of LLMetaProperty. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "metaproperty.h" - -#include "metaclass.h" - -LLMetaProperty::LLMetaProperty(const std::string& name, const LLMetaClass& object_class) : - mName(name), mObjectClass(object_class) -{ -} - -//virtual -LLMetaProperty::~LLMetaProperty() -{ -} - -const LLMetaClass& LLMetaProperty::getObjectMetaClass() const -{ - return mObjectClass; -} - -void LLMetaProperty::checkObjectClass(const LLReflective* object) const -{ - if(! mObjectClass.isInstance(object)) - { - throw "class cast exception"; - } -} diff --git a/indra/llcommon/metaproperty.h b/indra/llcommon/metaproperty.h deleted file mode 100755 index bd5bb1a30f..0000000000 --- a/indra/llcommon/metaproperty.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file metaproperty.h - * @author Babbage - * @date 2006-05-15 - * @brief Reflective meta information describing a property of a class. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METAPROPERTY_H -#define LL_METAPROPERTY_H - -#include "stdtypes.h" -#include "llsd.h" -#include "reflective.h" - -class LLMetaClass; -class LLReflective; -class LL_COMMON_API LLMetaProperty -{ -public: - LLMetaProperty(const std::string& name, const LLMetaClass& object_class); - virtual ~LLMetaProperty(); - - // Get property name. - const std::string& getName() const {return mName;} - - // Get value of this property. - virtual const LLReflective* get(const LLReflective* object) const = 0; - - // Set value of this property. - // virtual void set(LLReflective* object, const LLReflective* value) = 0; - - // Get value of this property as LLSD. Default returns undefined LLSD. - virtual LLSD getLLSD(const LLReflective* object) const = 0; - - // Get the MetaClass of legal values of this property. - // const LLMetaClass& getValueMetaClass(); - - // Get the meta class that this property is a member of. - const LLMetaClass& getObjectMetaClass() const; - -protected: - - // Check object is instance of object class, throw exception if not. - void checkObjectClass(const LLReflective* object) const; - -private: - - std::string mName; - const LLMetaClass& mObjectClass; -}; - -#endif // LL_METAPROPERTY_H diff --git a/indra/llcommon/metapropertyt.h b/indra/llcommon/metapropertyt.h deleted file mode 100755 index 7a36c161da..0000000000 --- a/indra/llcommon/metapropertyt.h +++ /dev/null @@ -1,183 +0,0 @@ -/** - * @file metapropertyt.h - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METAPROPERTYT_H -#define LL_METAPROPERTYT_H - -#include "llsd.h" -#include "llstring.h" -#include "metaclasst.h" -#include "metaproperty.h" -#include "reflectivet.h" - -template<class TProperty> -class LLMetaPropertyT : public LLMetaProperty -{ -public: - - virtual ~LLMetaPropertyT() {;} - - // Get value of this property. Gives ownership of returned value. - virtual const LLReflective* get(const LLReflective* object) const - { - checkObjectClass(object); - return getProperty(object); - } - - // Set value of this property. - /*virtual void set(LLReflective* object, const LLReflective* value) - { - // TODO: Babbage: Check types. - ref(object) = static_cast<const LLReflectiveT<TProperty>* >(value)->getValue(); - }*/ - - // Get value of this property as LLSD. - virtual LLSD getLLSD(const LLReflective* object) const - { - return LLSD(); - } - -protected: - - LLMetaPropertyT(const std::string& name, const LLMetaClass& object_class) : LLMetaProperty(name, object_class) {;} - - virtual const TProperty* getProperty(const LLReflective* object) const = 0; -}; - -template <> -inline const LLReflective* LLMetaPropertyT<S32>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline const LLReflective* LLMetaPropertyT<std::string>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline const LLReflective* LLMetaPropertyT<LLUUID>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline const LLReflective* LLMetaPropertyT<bool>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline LLSD LLMetaPropertyT<S32>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template <> -inline LLSD LLMetaPropertyT<std::string>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template <> -inline LLSD LLMetaPropertyT<LLUUID>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template <> -inline LLSD LLMetaPropertyT<bool>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template<class TObject, class TProperty> -class LLMetaPropertyTT : public LLMetaPropertyT<TProperty> -{ -public: - - LLMetaPropertyTT(const std::string& name, const LLMetaClass& object_class, TProperty (TObject::*property)) : - LLMetaPropertyT<TProperty>(name, object_class), mProperty(property) {;} - -protected: - - // Get void* to property. - virtual const TProperty* getProperty(const LLReflective* object) const - { - const TObject* typed_object = static_cast<const TObject*>(object); - return &(typed_object->*mProperty); - }; - -private: - - TProperty (TObject::*mProperty); -}; - -template<class TObject, class TProperty> -class LLMetaPropertyPtrTT : public LLMetaPropertyT<TProperty> -{ -public: - - LLMetaPropertyPtrTT(const std::string& name, const LLMetaClass& object_class, TProperty* (TObject::*property)) : - LLMetaPropertyT<TProperty>(name, object_class), mProperty(property) {;} - -protected: - - // Get void* to property. - virtual const TProperty* getProperty(const LLReflective* object) const - { - const TObject* typed_object = static_cast<const TObject*>(object); - return typed_object->*mProperty; - }; - -private: - - TProperty* (TObject::*mProperty); -}; - -// Utility function to simplify the registration of members. -template<class TObject, class TProperty> -void reflectProperty(LLMetaClass& meta_class, const std::string& name, TProperty (TObject::*property)) -{ - typedef LLMetaPropertyTT<TObject, TProperty> PropertyType; - const LLMetaProperty* meta_property = new PropertyType(name, meta_class, property); - meta_class.addProperty(meta_property); -} - -// Utility function to simplify the registration of ptr properties. -template<class TObject, class TProperty> -void reflectPtrProperty(LLMetaClass& meta_class, const std::string& name, TProperty* (TObject::*property)) -{ - typedef LLMetaPropertyPtrTT<TObject, TProperty> PropertyType; - const LLMetaProperty* meta_property = new PropertyType(name, meta_class, property); - meta_class.addProperty(meta_property); -} - -#endif // LL_METAPROPERTYT_H diff --git a/indra/llcommon/reflective.h b/indra/llcommon/reflective.h deleted file mode 100755 index da5c5a2630..0000000000 --- a/indra/llcommon/reflective.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file reflective.h - * @author Babbage - * @date 2006-05-15 - * @brief Interface that must be implemented by all reflective classes. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_REFLECTIVE_H -#define LL_REFLECTIVE_H - -class LLMetaClass; -class LL_COMMON_API LLReflective -{ -public: - LLReflective(); - virtual ~LLReflective(); - - virtual const LLMetaClass& getMetaClass() const = 0; -}; - -#endif // LL_REFLECTIVE_H diff --git a/indra/llcommon/reflectivet.h b/indra/llcommon/reflectivet.h deleted file mode 100755 index 958921f23e..0000000000 --- a/indra/llcommon/reflectivet.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file reflectivet.h - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_REFLECTIVET_H -#define LL_REFLECTIVET_H - -#include "reflective.h" - -template <class T> -class LLReflectiveT : public LLReflective -{ -public: - - LLReflectiveT(const T& value) : mValue(value) {;} - virtual ~LLReflectiveT() {;} - - virtual const LLMetaClass& getMetaClass() const {return LLMetaClassT<LLReflectiveT<T> >::instance();} - - const T& getValue() const {return mValue;} - -private: - - T mValue; -}; - -#endif diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp new file mode 100644 index 0000000000..a5df51f6de --- /dev/null +++ b/indra/llcommon/tests/llunits_test.cpp @@ -0,0 +1,219 @@ +/** + * @file llsingleton_test.cpp + * @date 2011-08-11 + * @brief Unit test for the LLSingleton class + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llunit.h" +#include "../test/lltut.h" + +namespace LLUnits +{ + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); + LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, * 4); + LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, / 16); +} + +namespace tut +{ + using namespace LLUnits; + struct units + { + }; + + typedef test_group<units> units_t; + typedef units_t::object units_object_t; + tut::units_t tut_singleton("LLUnit"); + + // storage type conversions + template<> template<> + void units_object_t::test<1>() + { + LLUnit<F32, Quatloos> float_quatloos; + ensure(float_quatloos == 0.f); + + LLUnit<F32, Quatloos> float_initialize_quatloos(1); + ensure(float_initialize_quatloos == 1.f); + + LLUnit<S32, Quatloos> int_quatloos; + ensure(int_quatloos == 0); + + int_quatloos = 42; + ensure(int_quatloos == 42); + float_quatloos = int_quatloos; + ensure(float_quatloos == 42.f); + + int_quatloos = float_quatloos; + ensure(int_quatloos == 42); + + float_quatloos = 42.1f; + ensure(float_quatloos == 42.1f); + int_quatloos = float_quatloos; + ensure(int_quatloos == 42); + LLUnit<U32, Quatloos> unsigned_int_quatloos(float_quatloos); + ensure(unsigned_int_quatloos == 42); + } + + // conversions to/from base unit + template<> template<> + void units_object_t::test<2>() + { + LLUnit<F32, Quatloos> quatloos(1.f); + ensure(quatloos == 1.f); + LLUnit<F32, Latinum> latinum_bars(quatloos); + ensure(latinum_bars == 1.f / 4.f); + + latinum_bars = 256; + quatloos = latinum_bars; + ensure(quatloos == 1024); + + LLUnit<F32, Solari> solari(quatloos); + ensure(solari == 4096); + } + + // conversions across non-base units + template<> template<> + void units_object_t::test<3>() + { + LLUnit<F32, Solari> solari = 4.f; + LLUnit<F32, Latinum> latinum_bars = solari; + ensure(latinum_bars == 0.25f); + } + + // math operations + template<> template<> + void units_object_t::test<4>() + { + LLUnit<F32, Quatloos> quatloos = 1.f; + quatloos *= 4.f; + ensure(quatloos == 4); + quatloos = quatloos * 2; + ensure(quatloos == 8); + quatloos = 2.f * quatloos; + ensure(quatloos == 16); + + quatloos += 4.f; + ensure(quatloos == 20); + quatloos += 4; + ensure(quatloos == 24); + quatloos = quatloos + 4; + ensure(quatloos == 28); + quatloos = 4 + quatloos; + ensure(quatloos == 32); + quatloos += quatloos * 3; + ensure(quatloos == 128); + + quatloos -= quatloos / 4 * 3; + ensure(quatloos == 32); + quatloos = quatloos - 8; + ensure(quatloos == 24); + quatloos -= 4; + ensure(quatloos == 20); + quatloos -= 4.f; + ensure(quatloos == 16); + + quatloos *= 2.f; + ensure(quatloos == 32); + quatloos = quatloos * 2.f; + ensure(quatloos == 64); + quatloos = 0.5f * quatloos; + ensure(quatloos == 32); + + quatloos /= 2.f; + ensure(quatloos == 16); + quatloos = quatloos / 4; + ensure(quatloos == 4); + + F32 ratio = quatloos / LLUnit<F32, Quatloos>(4.f); + ensure(ratio == 1); + ratio = quatloos / LLUnit<F32, Solari>(16.f); + ensure(ratio == 1); + + quatloos += LLUnit<F32, Solari>(4.f); + ensure(quatloos == 5); + quatloos -= LLUnit<F32, Latinum>(1.f); + ensure(quatloos == 1); + } + + // implicit units + template<> template<> + void units_object_t::test<5>() + { + // 0-initialized + LLUnit<F32, Quatloos> quatloos(0); + // initialize implicit unit from explicit + LLUnitImplicit<F32, Quatloos> quatloos_implicit = quatloos + 1; + ensure(quatloos_implicit == 1); + + // assign implicit to explicit, or perform math operations + quatloos = quatloos_implicit; + ensure(quatloos == 1); + quatloos += quatloos_implicit; + ensure(quatloos == 2); + + // math operations on implicits + quatloos_implicit = 1; + ensure(quatloos_implicit == 1); + + quatloos_implicit += 2; + ensure(quatloos_implicit == 3); + + quatloos_implicit *= 2; + ensure(quatloos_implicit == 6); + + quatloos_implicit -= 1; + ensure(quatloos_implicit == 5); + + quatloos_implicit /= 5; + ensure(quatloos_implicit == 1); + + quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit; + ensure(quatloos_implicit == 5); + + quatloos_implicit = 10 - quatloos_implicit - 1; + ensure(quatloos_implicit == 4); + + quatloos_implicit = 2 * quatloos_implicit * 2; + ensure(quatloos_implicit == 16); + + F32 one_half = quatloos_implicit / (quatloos_implicit * 2); + ensure(one_half == 0.5f); + + // implicit conversion to POD + F32 float_val = quatloos_implicit; + ensure(float_val == 16); + + S32 int_val = quatloos_implicit; + ensure(int_val == 16); + + // conversion of implicits + LLUnitImplicit<F32, Latinum> latinum_implicit(2); + ensure(latinum_implicit == 2); + + ensure(latinum_implicit * 2 == quatloos_implicit); + } +} diff --git a/indra/llcommon/tests/reflection_test.cpp b/indra/llcommon/tests/reflection_test.cpp deleted file mode 100755 index 8980ebb1f1..0000000000 --- a/indra/llcommon/tests/reflection_test.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file reflection_test.cpp - * @date May 2006 - * @brief Reflection unit tests. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "../linden_common.h" -#include "../reflective.h" -#include "../metaclasst.h" -#include "../metapropertyt.h" -#include "../stdtypes.h" - -#include "../test/lltut.h" - -namespace tut -{ - class TestAggregatedData : public LLReflective - { - public: - TestAggregatedData() {;} - virtual const LLMetaClass& getMetaClass() const; - - private: - }; - - class TestReflectionData : public LLReflective - { - public: - TestReflectionData() : mInt(42), mString("foo"), mNullPtr(NULL), mPtr(new TestAggregatedData()), mRef(*(new TestAggregatedData)) {;} - virtual ~TestReflectionData() {delete mPtr;} - virtual const LLMetaClass& getMetaClass() const; - - static U32 getPropertyCount() {return 5;} - - private: - - friend class LLMetaClassT<TestReflectionData>; - S32 mInt; - std::string mString; - TestAggregatedData* mNullPtr; - TestAggregatedData* mPtr; - TestAggregatedData mObj; - TestAggregatedData& mRef; - }; -} - -template <> -void LLMetaClassT<tut::TestReflectionData>::reflectProperties(LLMetaClass& meta_class) -{ - reflectProperty(meta_class, "mInt", &tut::TestReflectionData::mInt); - reflectProperty(meta_class, "mString", &tut::TestReflectionData::mString); - reflectPtrProperty(meta_class, "mNullPtr", &tut::TestReflectionData::mNullPtr); - reflectPtrProperty(meta_class, "mPtr", &tut::TestReflectionData::mPtr); - reflectProperty(meta_class, "mObj", &tut::TestReflectionData::mObj); - //reflectProperty(meta_class, "mRef", &tut::TestReflectionData::mRef); // AARGH! -} - -namespace tut -{ - // virtual - const LLMetaClass& TestReflectionData::getMetaClass() const - { - return LLMetaClassT<TestReflectionData>::instance(); - } - - const LLMetaClass& TestAggregatedData::getMetaClass() const - { - return LLMetaClassT<TestAggregatedData>::instance(); - } -} - -namespace tut -{ - typedef tut::test_group<TestReflectionData> TestReflectionGroup; - typedef TestReflectionGroup::object TestReflectionObject; - TestReflectionGroup gTestReflectionGroup("reflection"); - - template<> template<> - void TestReflectionObject::test<1>() - { - // Check properties can be found. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLMetaProperty* null = NULL; - ensure_not_equals(meta_class.findProperty("mInt"), null); - ensure_not_equals(meta_class.findProperty("mString"), null); - } - - template<> template<> - void TestReflectionObject::test<2>() - { - // Check non-existent property cannot be found. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLMetaProperty* null = NULL; - ensure_equals(meta_class.findProperty("foo"), null); - } - - template<> template<> - void TestReflectionObject::test<3>() - { - // Check integer property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - ensure_equals(meta_class.findProperty("mInt")->getLLSD(this).asInteger(), 42); - } - - template<> template<> - void TestReflectionObject::test<4>() - { - // Check string property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - ensure_equals(meta_class.findProperty("mString")->getLLSD(this).asString(), std::string("foo")); - } - - template<> template<> - void TestReflectionObject::test<5>() - { - // Check NULL reference property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLReflective* null = NULL; - ensure_equals(meta_class.findProperty("mNullPtr")->get(this), null); - } - - template<> template<> - void TestReflectionObject::test<6>() - { - // Check reference property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLReflective* null = NULL; - const LLReflective* ref = meta_class.findProperty("mPtr")->get(this); - ensure_not_equals(ref, null); - } - - template<> template<> - void TestReflectionObject::test<7>() - { - // Check reflective property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLReflective* null = NULL; - const LLReflective* ref = meta_class.findProperty("mObj")->get(this); - ensure_not_equals(ref, null); - } - - template<> template<> - void TestReflectionObject::test<8>() - { - // Check property count. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - ensure_equals(meta_class.getPropertyCount(), TestReflectionData::getPropertyCount()); - } - - template<> template<> - void TestReflectionObject::test<9>() - { - // Check property iteration. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - U32 count = 0; - LLMetaClass::PropertyIterator iter; - for(iter = meta_class.beginProperties(); iter != meta_class.endProperties(); ++iter) - { - ++count; - } - ensure_equals(count, TestReflectionData::getPropertyCount()); - } - - template<> template<> - void TestReflectionObject::test<10>() - { - // Check meta classes of different types do not compare equal. - const LLMetaClass* reflection_data_meta_class = &(LLMetaClassT<TestReflectionData>::instance()); - const LLMetaClass* aggregated_data_meta_class = &(LLMetaClassT<TestAggregatedData>::instance()); - ensure_not_equals(reflection_data_meta_class, aggregated_data_meta_class); - } - - template<> template<> - void TestReflectionObject::test<11>() - { - // Check class cast checks. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - TestAggregatedData* aggregated_data = new TestAggregatedData(); - LLMetaClass::PropertyIterator iter; - U32 exception_count = 0; - for(iter = meta_class.beginProperties(); iter != meta_class.endProperties(); ++iter) - { - try - { - const LLMetaProperty* property = (*iter).second; - const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception. - - // useless op to get rid of compiler warning. - reflective = reflective; - } - catch(...) - { - ++exception_count; - } - } - ensure_equals(exception_count, getPropertyCount()); - - } -} |