diff options
| author | Oz Linden <oz@lindenlab.com> | 2011-01-28 11:36:46 -0500 | 
|---|---|---|
| committer | Oz Linden <oz@lindenlab.com> | 2011-01-28 11:36:46 -0500 | 
| commit | 98140b3cdcd505aabe31fcd23db7a2603c8deed3 (patch) | |
| tree | b94c39ef7afbc4a091b1e4f2f7b4b2de599831a8 /indra/llcommon | |
| parent | 106c9124741afd50c3aaa5671743d5a939f1ad48 (diff) | |
| parent | 4b354802c10e6e947a0ce0f023158e22fcd5bc4b (diff) | |
merge changes for storm-634
Diffstat (limited to 'indra/llcommon')
24 files changed, 922 insertions, 26 deletions
| diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 7bad780dd8..9342a22d46 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -70,6 +70,7 @@ set(llcommon_SOURCE_FILES      llmemorystream.cpp      llmemtype.cpp      llmetrics.cpp +    llmetricperformancetester.cpp      llmortician.cpp      lloptioninterface.cpp      llptrto.cpp  @@ -92,6 +93,7 @@ set(llcommon_SOURCE_FILES      llstringtable.cpp      llsys.cpp      llthread.cpp +    llthreadsafequeue.cpp      lltimer.cpp      lluri.cpp      lluuid.cpp @@ -186,6 +188,7 @@ set(llcommon_HEADER_FILES      llmemorystream.h      llmemtype.h      llmetrics.h +    llmetricperformancetester.h      llmortician.h      llnametable.h      lloptioninterface.h @@ -223,6 +226,7 @@ set(llcommon_HEADER_FILES      llstringtable.h      llsys.h      llthread.h +    llthreadsafequeue.h      lltimer.h      lltreeiterators.h      lluri.h diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index b0618bfe59..95cb606240 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -245,9 +245,6 @@ const U8 SIM_ACCESS_ADULT	= 42;		// Seriously Adult Only  const U8 SIM_ACCESS_DOWN	= 254;  const U8 SIM_ACCESS_MAX 	= SIM_ACCESS_ADULT; -// group constants -const S32 MAX_AGENT_GROUPS = 25; -  // attachment constants  const S32 MAX_AGENT_ATTACHMENTS = 38;  const U8  ATTACHMENT_ADD = 0x80; @@ -300,6 +297,14 @@ const U32 START_LOCATION_ID_COUNT 		= 6;  // group constants  const U32 GROUP_MIN_SIZE = 2; +// gMaxAgentGroups is now sent by login.cgi, which +// looks it up from globals.xml. +// +// For now we need an old default value however, +// so the viewer can be deployed ahead of login.cgi. +// +const S32 DEFAULT_MAX_AGENT_GROUPS = 25; +  // radius within which a chat message is fully audible  const F32 CHAT_WHISPER_RADIUS = 10.f;  const F32 CHAT_NORMAL_RADIUS = 20.f; diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index eebd5ed0a6..39daefd1ad 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -90,6 +90,10 @@ S32 LL_HEARTBEAT_SIGNAL = (SIGRTMAX >= 0) ? (SIGRTMAX-0) : SIGUSR2;  // the static application instance  LLApp* LLApp::sApplication = NULL; +// Allows the generation of core files for post mortem under gdb +// and disables crashlogger +BOOL LLApp::sDisableCrashlogger = FALSE;  +  // Local flag for whether or not to do logging in signal handlers.  //static  BOOL LLApp::sLogInSignal = FALSE; @@ -461,11 +465,30 @@ bool LLApp::isQuitting()  	return (APP_STATUS_QUITTING == sStatus);  } +// static  bool LLApp::isExiting()  {  	return isQuitting() || isError();  } +void LLApp::disableCrashlogger() +{ +	// Disable Breakpad exception handler. +	if (mExceptionHandler != 0) +	{ +		delete mExceptionHandler; +		mExceptionHandler = 0; +	} + +	sDisableCrashlogger = TRUE; +} + +// static +bool LLApp::isCrashloggerDisabled() +{ +	return (sDisableCrashlogger == TRUE);  +} +  #if !LL_WINDOWS  // static  U32 LLApp::getSigChildCount() @@ -799,6 +822,15 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)  			{  				llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl;  			} +									 +			if (LLApp::isCrashloggerDisabled())	// Don't gracefully handle any signal, crash and core for a gdb post mortem +			{ +				clear_signals(); +				llwarns << "Fatal signal received, not handling the crash here, passing back to operating system" << llendl; +				raise(signum); +				return; +			}		 +			  			// Flag status to ERROR, so thread_error does its work.  			LLApp::setError();  			// Block in the signal handler until somebody says that we're done. diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index ee1d696829..a536a06ea5 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -189,6 +189,11 @@ public:  	//  	virtual bool mainLoop() = 0; // Override for the application main loop.  Needs to at least gracefully notice the QUITTING state and exit. +	// +	// Crash logging +	// +	void disableCrashlogger();				// Let the OS handle the crashes +	static bool isCrashloggerDisabled();	// Get the here above set value  	//  	// Application status @@ -280,6 +285,7 @@ protected:  	static void setStatus(EAppStatus status);		// Use this to change the application status.  	static EAppStatus sStatus; // Reflects current application status  	static BOOL sErrorThreadRunning; // Set while the error thread is running +	static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.  #if !LL_WINDOWS  	static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received. diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 66ec5bad2c..d1c44c9403 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -28,6 +28,7 @@  #include "linden_common.h"  #include "llapr.h" +#include "apr_dso.h"  apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool  LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool. @@ -279,14 +280,31 @@ bool ll_apr_warn_status(apr_status_t status)  {  	if(APR_SUCCESS == status) return false;  	char buf[MAX_STRING];	/* Flawfinder: ignore */ -	apr_strerror(status, buf, MAX_STRING); +	apr_strerror(status, buf, sizeof(buf));  	LL_WARNS("APR") << "APR: " << buf << LL_ENDL;  	return true;  } +bool ll_apr_warn_status(apr_status_t status, apr_dso_handle_t *handle) +{ +    bool result = ll_apr_warn_status(status); +    // Despite observed truncation of actual Mac dylib load errors, increasing +    // this buffer to more than MAX_STRING doesn't help: it appears that APR +    // stores the output in a fixed 255-character internal buffer. (*sigh*) +    char buf[MAX_STRING];           /* Flawfinder: ignore */ +    apr_dso_error(handle, buf, sizeof(buf)); +    LL_WARNS("APR") << "APR: " << buf << LL_ENDL; +    return result; +} +  void ll_apr_assert_status(apr_status_t status)  { -	llassert(ll_apr_warn_status(status) == false); +	llassert(! ll_apr_warn_status(status)); +} + +void ll_apr_assert_status(apr_status_t status, apr_dso_handle_t *handle) +{ +    llassert(! ll_apr_warn_status(status, handle));  }  //--------------------------------------------------------------------- diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 4930270af8..af33ce666f 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -53,6 +53,8 @@  extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;  extern apr_thread_mutex_t* gCallStacksLogMutexp; +struct apr_dso_handle_t; +  /**    * @brief initialize the common apr constructs -- apr itself, the   * global pool, and a mutex. @@ -259,8 +261,11 @@ public:   * @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 diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp index b1ec9e9875..ad1845d387 100644 --- a/indra/llcommon/llavatarname.cpp +++ b/indra/llcommon/llavatarname.cpp @@ -48,7 +48,7 @@ LLAvatarName::LLAvatarName()  	mLegacyFirstName(),  	mLegacyLastName(),  	mIsDisplayNameDefault(false), -	mIsDummy(false), +	mIsTemporaryName(false),  	mExpires(F64_MAX),  	mNextUpdate(0.0)  { } diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h index 145aeccd35..ba258d6d52 100644 --- a/indra/llcommon/llavatarname.h +++ b/indra/llcommon/llavatarname.h @@ -79,7 +79,7 @@ public:  	// Under error conditions, we may insert "dummy" records with  	// names like "???" into caches as placeholders.  These can be  	// shown in UI, but are not serialized. -	bool mIsDummy; +	bool mIsTemporaryName;  	// Names can change, so need to keep track of when name was  	// last checked. diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h index a8cd03b42a..131b819c99 100644 --- a/indra/llcommon/lldarray.h +++ b/indra/llcommon/lldarray.h @@ -51,7 +51,7 @@ public:  	LLDynamicArray(S32 size=0) : std::vector<Type>(size) { if (size < BlockSize) std::vector<Type>::reserve(BlockSize); } -	void reset() { std::vector<Type>::resize(0); } +	void reset() { std::vector<Type>::clear(); }  	// ACCESSORS  	const Type& get(S32 index) const	 			{ return std::vector<Type>::operator[](index); } diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 84a6620a77..97e2bdeb57 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -475,7 +475,7 @@ void LLEventPump::stopListening(const std::string& name)  *****************************************************************************/  bool LLEventStream::post(const LLSD& event)  { -    if (! mEnabled) +    if (! mEnabled || !mSignal)      {          return false;      } @@ -515,6 +515,8 @@ bool LLEventQueue::post(const LLSD& event)  void LLEventQueue::flush()  { +	if(!mSignal) return; +		      // Consider the case when a given listener on this LLEventQueue posts yet      // another event on the same queue. If we loop over mEventQueue directly,      // we'll end up processing all those events during the same flush() call diff --git a/indra/llcommon/llfasttimer_class.cpp b/indra/llcommon/llfasttimer_class.cpp index c45921cdec..bce87ada96 100644 --- a/indra/llcommon/llfasttimer_class.cpp +++ b/indra/llcommon/llfasttimer_class.cpp @@ -56,6 +56,7 @@ 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; diff --git a/indra/llcommon/llfasttimer_class.h b/indra/llcommon/llfasttimer_class.h index 1158ac5140..eb9789682b 100644 --- a/indra/llcommon/llfasttimer_class.h +++ b/indra/llcommon/llfasttimer_class.h @@ -211,6 +211,7 @@ public:  	static std::queue<LLSD> sLogQueue;  	static BOOL				sLog;  	static BOOL				sMetricLog; +	static std::string		sLogName;  	static bool 			sPauseHistory;  	static bool 			sResetHistory;  	static U64				sTimerCycles; diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 289ce0bc2c..8f02391e75 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -318,7 +318,12 @@ void llofstream::close()  	if(is_open())  	{  		if (_Filebuffer->close() == 0) +		{  			_Myios::setstate(ios_base::failbit);	/*Flawfinder: ignore*/ +		} +		delete _Filebuffer; +		_Filebuffer = NULL; +		_ShouldClose = false;  	}  } diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp new file mode 100644 index 0000000000..5fa3a5ea07 --- /dev/null +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -0,0 +1,254 @@ +/**  + * @file llmetricperformancetester.cpp + * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes implementation + * + * $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 "indra_constants.h" +#include "llerror.h" +#include "llsdserialize.h" +#include "llstat.h" +#include "lltreeiterators.h" +#include "llmetricperformancetester.h" + +//---------------------------------------------------------------------------------------------- +// LLMetricPerformanceTesterBasic : static methods and testers management +//---------------------------------------------------------------------------------------------- + +LLMetricPerformanceTesterBasic::name_tester_map_t LLMetricPerformanceTesterBasic::sTesterMap ; + +/*static*/  +void LLMetricPerformanceTesterBasic::cleanClass()  +{ +	for (name_tester_map_t::iterator iter = sTesterMap.begin() ; iter != sTesterMap.end() ; ++iter) +	{ +		delete iter->second ; +	} +	sTesterMap.clear() ; +} + +/*static*/  +BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester)  +{ +	llassert_always(tester != NULL);	 +	std::string name = tester->getTesterName() ; +	if (getTester(name)) +	{ +		llerrs << "Tester name is already used by some other tester : " << name << llendl ; +		return FALSE; +	} + +	sTesterMap.insert(std::make_pair(name, tester)); +	return TRUE; +} +	 +/*static*/  +LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name)  +{ +	// Check for the requested metric name +	name_tester_map_t::iterator found_it = sTesterMap.find(name) ; +	if (found_it != sTesterMap.end()) +	{ +		return found_it->second ; +	} +	return NULL ; +} + +/*static*/  +// 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))); +} + +	 +//---------------------------------------------------------------------------------------------- +// LLMetricPerformanceTesterBasic : Tester instance methods +//---------------------------------------------------------------------------------------------- + +LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) :  +	mName(name), +	mCount(0) +{ +	if (mName == std::string()) +	{ +		llerrs << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << llendl ; +	} + +	mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ; +} + +LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic()  +{ +} + +void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)  +{ +	incrementCurrentCount() ; +	(*sd)[getCurrentLabelName()]["Name"] = mName ; +} + +void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd) +{ +	LLMutexLock lock(LLFastTimer::sLogLock); +	LLFastTimer::sLogQueue.push((*sd)); +} + +void LLMetricPerformanceTesterBasic::outputTestResults()  +{ +	LLSD sd; + +	preOutputTestResults(&sd) ;  +	outputTestRecord(&sd) ; +	postOutputTestResults(&sd) ; +} + +void LLMetricPerformanceTesterBasic::addMetric(std::string str) +{ +	mMetricStrings.push_back(str) ; +} + +/*virtual*/  +void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)  +{ +	resetCurrentCount() ; + +	std::string current_label = getCurrentLabelName(); +	BOOL in_base = (*base).has(current_label) ; +	BOOL in_current = (*current).has(current_label) ; + +	while(in_base || in_current) +	{ +		LLSD::String label = current_label ;		 + +		if(in_base && in_current) +		{				 +			*os << llformat("%s\n", label.c_str()) ; + +			for(U32 index = 0 ; index < mMetricStrings.size() ; index++) +			{ +				switch((*current)[label][ mMetricStrings[index] ].type()) +				{ +				case LLSD::TypeInteger: +					compareTestResults(os, mMetricStrings[index],  +						(S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ; +					break ; +				case LLSD::TypeReal: +					compareTestResults(os, mMetricStrings[index],  +						(F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ; +					break; +				default: +					llerrs << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << llendl ; +				} +			}	 +		} + +		incrementCurrentCount(); +		current_label = getCurrentLabelName(); +		in_base = (*base).has(current_label) ; +		in_current = (*current).has(current_label) ; +	} +} + +/*virtual*/  +void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current)  +{ +	*os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current,  +						v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ; +} + +/*virtual*/  +void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current)  +{ +	*os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current,						 +						v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ; +} + +//---------------------------------------------------------------------------------------------- +// LLMetricPerformanceTesterWithSession +//---------------------------------------------------------------------------------------------- + +LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) :  +	LLMetricPerformanceTesterBasic(name), +	mBaseSessionp(NULL), +	mCurrentSessionp(NULL) +{ +} + +LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession() +{ +	if (mBaseSessionp) +	{ +		delete mBaseSessionp ; +		mBaseSessionp = NULL ; +	} +	if (mCurrentSessionp) +	{ +		delete mCurrentSessionp ; +		mCurrentSessionp = NULL ; +	} +} + +/*virtual*/  +void LLMetricPerformanceTesterWithSession::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current)  +{ +	// Load the base session +	resetCurrentCount() ; +	mBaseSessionp = loadTestSession(base) ; + +	// Load the current session +	resetCurrentCount() ; +	mCurrentSessionp = loadTestSession(current) ; + +	if (!mBaseSessionp || !mCurrentSessionp) +	{ +		llerrs << "Error loading test sessions." << llendl ; +	} + +	// Compare +	compareTestSessions(os) ; + +	// Release memory +	if (mBaseSessionp) +	{ +		delete mBaseSessionp ; +		mBaseSessionp = NULL ; +	} +	if (mCurrentSessionp) +	{ +		delete mCurrentSessionp ; +		mCurrentSessionp = NULL ; +	} +} + + +//---------------------------------------------------------------------------------------------- +// LLTestSession +//---------------------------------------------------------------------------------------------- + +LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession()  +{ +} + diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h new file mode 100644 index 0000000000..925010ac96 --- /dev/null +++ b/indra/llcommon/llmetricperformancetester.h @@ -0,0 +1,206 @@ +/**  + * @file llmetricperformancetester.h  + * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes definition + * + * $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_METRICPERFORMANCETESTER_H  +#define LL_METRICPERFORMANCETESTER_H  + +const std::string DEFAULT_METRIC_NAME("metric"); + +/** + * @class LLMetricPerformanceTesterBasic + * @brief Performance Metric Base Class + */ +class LL_COMMON_API LLMetricPerformanceTesterBasic +{ +public: +	/** +	 * @brief Creates a basic tester instance. +	 * @param[in] name - Unique string identifying this tester instance. +	 */ +	LLMetricPerformanceTesterBasic(std::string name); +	virtual ~LLMetricPerformanceTesterBasic(); + +	/** +	 * @return Returns true if the instance has been added to the tester map. +	 * Need to be tested after creation of a tester instance so to know if the tester is correctly handled. +	 * A tester might not be added to the map if another tester with the same name already exists. +	 */ +	BOOL isValid() const { return mValidInstance; } + +	/** +	 * @brief Write a set of test results to the log LLSD. +	 */ +	void outputTestResults() ; + +	/** +	 * @brief Compare the test results. +	 * By default, compares the test results against the baseline one by one, item by item,  +	 * in the increasing order of the LLSD record counter, starting from the first one. +	 */ +	virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ; + +	/** +	 * @return Returns the number of the test metrics in this tester instance. +	 */ +	S32 getNumberOfMetrics() const { return mMetricStrings.size() ;} +	/** +	 * @return Returns the metric name at index +	 * @param[in] index - Index on the list of metrics managed by this tester instance. +	 */ +	std::string getMetricName(S32 index) const { return mMetricStrings[index] ;} + +protected: +	/** +	 * @return Returns the name of this tester instance. +	 */ +	std::string getTesterName() const { return mName ;} + +	/** +	 * @brief Insert a new metric to be managed by this tester instance. +	 * @param[in] str - Unique string identifying the new metric. +	 */ +	void addMetric(std::string str) ; + +	/** +	 * @brief Compare test results, provided in 2 flavors: compare integers and compare floats. +	 * @param[out] os - Formatted output string holding the compared values. +	 * @param[in] metric_string - Name of the metric. +	 * @param[in] v_base - Base value of the metric. +	 * @param[in] v_current - Current value of the metric. +	 */ +	virtual void compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current) ; +	virtual void compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current) ; + +	/** +	 * @brief Reset internal record count. Count starts with 1. +	 */ +	void resetCurrentCount() { mCount = 1; } +	/** +	 * @brief Increment internal record count. +	 */ +	void incrementCurrentCount() { mCount++; } +	/** +	 * @return Returns the label to be used for the current count. It's "TesterName"-"Count". +	 */ +	std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;} + +	/** +	 * @brief Write a test record to the LLSD. Implementers need to overload this method. +	 * @param[out] sd - The LLSD record to store metric data into. +	 */ +	virtual void outputTestRecord(LLSD* sd) = 0 ; + +private: +	void preOutputTestResults(LLSD* sd) ; +	void postOutputTestResults(LLSD* sd) ; + +	std::string mName ;							// Name of this tester instance +	S32 mCount ;								// Current record count +	BOOL mValidInstance;						// TRUE if the instance is managed by the map +	std::vector< std::string > mMetricStrings ; // Metrics strings + +// Static members managing the collection of testers +public:	 +	// Map of all the tester instances in use +	typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t;	 +	static name_tester_map_t sTesterMap ; + +	/** +	 * @return Returns a pointer to the tester +	 * @param[in] name - Name of the tester instance queried. +	 */ +	static LLMetricPerformanceTesterBasic* getTester(std::string name) ; +	 +	/** +	 * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged +	 * @param[in] name - Name of the tester queried. +	 */ +	static BOOL isMetricLogRequested(std::string name); +	 +	/** +	 * @return Returns TRUE if there's a tester defined, FALSE otherwise. +	 */ +	static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;} +	/** +	 * @brief Delete all testers and reset the tester map +	 */ +	static void cleanClass() ; + +private: +	// Add a tester to the map. Returns false if adding fails. +	static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ; +}; + +/** + * @class LLMetricPerformanceTesterWithSession + * @brief Performance Metric Class with custom session  + */ +class LL_COMMON_API LLMetricPerformanceTesterWithSession : public LLMetricPerformanceTesterBasic +{ +public: +	/** +	 * @param[in] name - Unique string identifying this tester instance. +	 */ +	LLMetricPerformanceTesterWithSession(std::string name); +	virtual ~LLMetricPerformanceTesterWithSession(); + +	/** +	 * @brief Compare the test results. +	 * This will be loading the base and current sessions and compare them using the virtual  +	 * abstract methods loadTestSession() and compareTestSessions() +	 */ +	virtual void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ; + +protected: +	/** +	 * @class LLMetricPerformanceTesterWithSession::LLTestSession +	 * @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions() +	 */ +	class LL_COMMON_API LLTestSession +		{ +		public: +			virtual ~LLTestSession() ; +		}; + +	/** +	 * @brief Convert an LLSD log into a test session. +	 * @param[in] log - The LLSD record +	 * @return Returns the record as a test session +	 */ +	virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0; + +	/** +	 * @brief Compare the base session and the target session. Assumes base and current sessions have been loaded. +	 * @param[out] os - The comparison result as a standard stream +	 */ +	virtual void compareTestSessions(std::ofstream* os) = 0; + +	LLTestSession* mBaseSessionp; +	LLTestSession* mCurrentSessionp; +}; + +#endif + diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp index 99308c94e7..4b0f6b0251 100644 --- a/indra/llcommon/llprocesslauncher.cpp +++ b/indra/llcommon/llprocesslauncher.cpp @@ -58,6 +58,11 @@ void LLProcessLauncher::setWorkingDirectory(const std::string &dir)  	mWorkingDir = dir;  } +const std::string& LLProcessLauncher::getExecutable() const +{ +	return mExecutable; +} +  void LLProcessLauncher::clearArguments()  {  	mLaunchArguments.clear(); @@ -260,14 +265,7 @@ int LLProcessLauncher::launch(void)  	delete[] fake_argv;  	mProcessID = id; -	 -	// At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked) -	// If the process doesn't exist at this point, the exec failed. -	if(!isRunning()) -	{ -		result = -1; -	} -	 +  	return result;  } diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h index 479aeb664a..954c249147 100644 --- a/indra/llcommon/llprocesslauncher.h +++ b/indra/llcommon/llprocesslauncher.h @@ -47,6 +47,8 @@ public:  	void setExecutable(const std::string &executable);  	void setWorkingDirectory(const std::string &dir); +	const std::string& getExecutable() const; +  	void clearArguments();  	void addArgument(const std::string &arg);  	void addArgument(const char *arg); diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index c75e0e2bbf..a53b22f6fc 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -179,7 +179,7 @@ public:  	void waitOnPending();  	void printQueueStats(); -	S32 getPending(); +	virtual S32 getPending();  	bool getThreaded() { return mThreaded ? true : false; }  	// Request accessors diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 00c94404d4..10cdc7087b 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -635,6 +635,26 @@ U32 LLMemoryInfo::getPhysicalMemoryClamped() const  	}  } +//static +void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb) +{ +#if LL_WINDOWS +	MEMORYSTATUSEX state; +	state.dwLength = sizeof(state); +	GlobalMemoryStatusEx(&state); + +	avail_physical_mem_kb = (U32)(state.ullAvailPhys/1024) ; +	avail_virtual_mem_kb = (U32)(state.ullAvailVirtual/1024) ; + +#else +	//do not know how to collect available memory info for other systems. +	//leave it blank here for now. + +	avail_physical_mem_kb = -1 ; +	avail_virtual_mem_kb = -1 ; +#endif +} +  void LLMemoryInfo::stream(std::ostream& s) const  {  #if LL_WINDOWS diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index 39af74e5c8..41a4f25000 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -114,6 +114,9 @@ public:  	**  be returned.  	*/  	U32 getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes + +	//get the available memory infomation in KiloBytes. +	static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb);  }; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index d7b7c3699c..49d05ef411 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -63,9 +63,6 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap  {  	LLThread *threadp = (LLThread *)datap; -	// Set thread state to running -	threadp->mStatus = RUNNING; -  	// Run the user supplied function  	threadp->run(); @@ -147,26 +144,45 @@ void LLThread::shutdown()  		{  			// This thread just wouldn't stop, even though we gave it time  			llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; +			// Put a stake in its heart. +			apr_thread_exit(mAPRThreadp, -1);  			return;  		}  		mAPRThreadp = NULL;  	}  	delete mRunCondition; +	mRunCondition = 0; -	if (mIsLocalPool) +	if (mIsLocalPool && mAPRPoolp)  	{  		apr_pool_destroy(mAPRPoolp); +		mAPRPoolp = 0;  	}  }  void LLThread::start()  { -	apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);	 +	llassert(isStopped()); +	 +	// Set thread state to running +	mStatus = RUNNING; -	// We won't bother joining -	apr_thread_detach(mAPRThreadp); +	apr_status_t status = +		apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp); +	 +	if(status == APR_SUCCESS) +	{	 +		// We won't bother joining +		apr_thread_detach(mAPRThreadp); +	} +	else +	{ +		mStatus = STOPPED; +		llwarns << "failed to start thread " << mName << llendl; +		ll_apr_warn_status(status); +	}  }  //============================================================================ diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp new file mode 100644 index 0000000000..8a73e632a9 --- /dev/null +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -0,0 +1,109 @@ +/**  + * @file llthread.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 <apr_pools.h> +#include <apr_queue.h> +#include "llthreadsafequeue.h" + + + +// LLThreadSafeQueueImplementation +//----------------------------------------------------------------------------- + + +LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity): +	mOwnsPool(pool == 0), +	mPool(pool), +	mQueue(0) +{ +	if(mOwnsPool) { +		apr_status_t status = apr_pool_create(&mPool, 0); +		if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate pool"); +	} else { +		; // No op. +	} +	 +	apr_status_t status = apr_queue_create(&mQueue, capacity, mPool); +	if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue"); +} + + +LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation() +{ +	if(mQueue != 0) { +		if(apr_queue_size(mQueue) != 0) llwarns <<  +			"terminating queue which still contains " << apr_queue_size(mQueue) << +			" elements;" << "memory will be leaked" << LL_ENDL; +		apr_queue_term(mQueue); +	} +	if(mOwnsPool && (mPool != 0)) apr_pool_destroy(mPool); +} + + +void LLThreadSafeQueueImplementation::pushFront(void * element) +{ +	apr_status_t status = apr_queue_push(mQueue, element); +	 +	if(status == APR_EINTR) { +		throw LLThreadSafeQueueInterrupt(); +	} else if(status != APR_SUCCESS) { +		throw LLThreadSafeQueueError("push failed"); +	} else { +		; // Success. +	} +} + + +bool LLThreadSafeQueueImplementation::tryPushFront(void * element){ +	return apr_queue_trypush(mQueue, element) == APR_SUCCESS; +} + + +void * LLThreadSafeQueueImplementation::popBack(void) +{ +	void * element; +	apr_status_t status = apr_queue_pop(mQueue, &element); + +	if(status == APR_EINTR) { +		throw LLThreadSafeQueueInterrupt(); +	} else if(status != APR_SUCCESS) { +		throw LLThreadSafeQueueError("pop failed"); +	} else { +		return element; +	} +} + + +bool LLThreadSafeQueueImplementation::tryPopBack(void *& element) +{ +	return apr_queue_trypop(mQueue, &element) == APR_SUCCESS; +} + + +size_t LLThreadSafeQueueImplementation::size() +{ +	return apr_queue_size(mQueue); +} diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h new file mode 100644 index 0000000000..58cac38769 --- /dev/null +++ b/indra/llcommon/llthreadsafequeue.h @@ -0,0 +1,205 @@ +/**  + * @file llthreadsafequeue.h + * @brief Base classes for thread, mutex and condition handling. + * + * $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_LLTHREADSAFEQUEUE_H +#define LL_LLTHREADSAFEQUEUE_H + + +#include <string> +#include <stdexcept> + + +struct apr_pool_t; // From apr_pools.h +class LLThreadSafeQueueImplementation; // See below. + + +// +// A general queue exception. +// +class LL_COMMON_API LLThreadSafeQueueError: +public std::runtime_error +{ +public: +	LLThreadSafeQueueError(std::string const & message): +	std::runtime_error(message) +	{ +		; // No op. +	} +}; + + +// +// An exception raised when blocking operations are interrupted. +// +class LL_COMMON_API LLThreadSafeQueueInterrupt: +	public LLThreadSafeQueueError +{ +public: +	LLThreadSafeQueueInterrupt(void): +		LLThreadSafeQueueError("queue operation interrupted") +	{ +		; // No op. +	} +}; + + +struct apr_queue_t; // From apr_queue.h + + +// +// Implementation details.  +// +class LL_COMMON_API LLThreadSafeQueueImplementation +{ +public: +	LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity); +	~LLThreadSafeQueueImplementation(); +	void pushFront(void * element); +	bool tryPushFront(void * element); +	void * popBack(void); +	bool tryPopBack(void *& element); +	size_t size(); +	 +private: +	bool mOwnsPool; +	apr_pool_t * mPool; +	apr_queue_t * mQueue; +}; + + +// +// Implements a thread safe FIFO. +// +template<typename ElementT> +class LLThreadSafeQueue +{ +public: +	typedef ElementT value_type; +	 +	// If the pool is set to NULL one will be allocated and managed by this +	// queue. +	LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024); +	 +	// Add an element to the front of queue (will block if the queue has +	// reached capacity). +	// +	// This call will raise an interrupt error if the queue is deleted while +	// the caller is blocked. +	void pushFront(ElementT const & element); +	 +	// Try to add an element to the front ofqueue without blocking. Returns +	// true only if the element was actually added. +	bool tryPushFront(ElementT const & element); +	 +	// Pop the element at the end of the queue (will block if the queue is +	// empty). +	// +	// This call will raise an interrupt error if the queue is deleted while +	// the caller is blocked. +	ElementT popBack(void); +	 +	// Pop an element from the end of the queue if there is one available. +	// Returns true only if an element was popped. +	bool tryPopBack(ElementT & element); +	 +	// Returns the size of the queue. +	size_t size(); + +private: +	LLThreadSafeQueueImplementation mImplementation; +}; + + + +// LLThreadSafeQueue +//----------------------------------------------------------------------------- + + +template<typename ElementT> +LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity): +	mImplementation(pool, capacity) +{ +	; // No op. +} + + +template<typename ElementT> +void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element) +{ +	ElementT * elementCopy = new ElementT(element); +	try { +		mImplementation.pushFront(elementCopy); +	} catch (LLThreadSafeQueueInterrupt) { +		delete elementCopy; +		throw; +	} +} + + +template<typename ElementT> +bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element) +{ +	ElementT * elementCopy = new ElementT(element); +	bool result = mImplementation.tryPushFront(elementCopy); +	if(!result) delete elementCopy; +	return result; +} + + +template<typename ElementT> +ElementT LLThreadSafeQueue<ElementT>::popBack(void) +{ +	ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack()); +	ElementT result(*element); +	delete element; +	return result; +} + + +template<typename ElementT> +bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element) +{ +	void * storedElement; +	bool result = mImplementation.tryPopBack(storedElement); +	if(result) { +		ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);  +		element = *elementPtr; +		delete elementPtr; +	} else { +		; // No op. +	} +	return result; +} + + +template<typename ElementT> +size_t LLThreadSafeQueue<ElementT>::size(void) +{ +	return mImplementation.size(); +} + + +#endif diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 12bddbfeed..356e0f4c0f 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -28,10 +28,14 @@  #define LL_LLVERSIONVIEWER_H  const S32 LL_VERSION_MAJOR = 2; -const S32 LL_VERSION_MINOR = 3; +const S32 LL_VERSION_MINOR = 5;  const S32 LL_VERSION_PATCH = 0;  const S32 LL_VERSION_BUILD = 0;  const char * const LL_CHANNEL = "Second Life Developer"; +#if LL_DARWIN +const char * const LL_VERSION_BUNDLE_ID = "com.secondlife.indra.viewer"; +#endif +  #endif | 
