From 39e5d2ecf04deceda92d6a53413298ca1c3bc0c7 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 8 Sep 2010 23:03:56 -0700 Subject: VWR-22761 : Rearchitecture of llmetricperformancetester and simple (non complete) implementation in llimagej2c --- indra/llcommon/CMakeLists.txt | 2 + indra/llcommon/llmetricperformancetester.cpp | 245 +++++++++++++++++++++++++++ indra/llcommon/llmetricperformancetester.h | 197 +++++++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 indra/llcommon/llmetricperformancetester.cpp create mode 100644 indra/llcommon/llmetricperformancetester.h (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 2a036df06e..000648206f 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -54,6 +54,7 @@ set(llcommon_SOURCE_FILES llevents.cpp lleventtimer.cpp llfasttimer_class.cpp + llmetricperformancetester.cpp llfile.cpp llfindlocale.cpp llfixedbuffer.cpp @@ -157,6 +158,7 @@ set(llcommon_HEADER_FILES lleventemitter.h llextendedstatus.h llfasttimer.h + llmetricperformancetester.h llfile.h llfindlocale.h llfixedbuffer.h diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp new file mode 100644 index 0000000000..bd548f199a --- /dev/null +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -0,0 +1,245 @@ +/** + * @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) +{ + name_tester_map_t::iterator found_it = sTesterMap.find(name) ; + if (found_it != sTesterMap.end()) + { + return found_it->second ; + } + return NULL ; +} + +//---------------------------------------------------------------------------------------------- +// 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 currentLabel = getCurrentLabelName(); + BOOL in_base = (*base).has(currentLabel) ; + BOOL in_current = (*current).has(currentLabel) ; + + while(in_base || in_current) + { + LLSD::String label = currentLabel ; + + 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(); + currentLabel = getCurrentLabelName(); + in_base = (*base).has(currentLabel) ; + in_current = (*current).has(currentLabel) ; + } +} + +/*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..82d579b188 --- /dev/null +++ b/indra/llcommon/llmetricperformancetester.h @@ -0,0 +1,197 @@ +/** + * @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 + +/** + * @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 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 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 + -- cgit v1.3 From 40979589afc5c91cab977307a1e400315b1c8a8f Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 27 Oct 2010 23:15:22 -0700 Subject: STORM-105 : improve decompression perf gathering, allow perf name to be passed on the command line, fix crash in analysis phase --- indra/llcommon/llfasttimer_class.cpp | 1 + indra/llcommon/llfasttimer_class.h | 1 + indra/llimage/llimagej2c.cpp | 80 +++++++++++++++++++++++---------- indra/llimage/llimagej2c.h | 4 +- indra/newview/app_settings/cmd_line.xml | 2 + indra/newview/llappviewer.cpp | 52 ++++++++++----------- indra/newview/llappviewer.h | 4 +- indra/newview/llfasttimerview.cpp | 25 +++++++++-- indra/newview/llviewertexture.cpp | 6 +-- 9 files changed, 118 insertions(+), 57 deletions(-) (limited to 'indra/llcommon') 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 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 sLogQueue; static BOOL sLog; static BOOL sMetricLog; + static std::string sLogName; static bool sPauseHistory; static bool sResetHistory; static U64 sTimerCycles; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 207728d4d9..08a5912c57 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -31,6 +31,7 @@ #include "llimagej2c.h" #include "llmemtype.h" #include "lltimer.h" +#include "llmath.h" typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)(); typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*); @@ -54,6 +55,7 @@ const char* fallbackEngineInfoLLImageJ2CImpl(); // Test data gathering handle LLImageCompressionTester* LLImageJ2C::sTesterp = NULL ; +const std::string sTesterName("ImageCompressionTester"); //static //Loads the required "create", "destroy" and "engineinfo" functions needed @@ -200,7 +202,7 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mDataSizes[i] = 0; } - if (LLFastTimer::sMetricLog && !LLImageJ2C::sTesterp) + if (LLFastTimer::sMetricLog && !LLImageJ2C::sTesterp && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) { LLImageJ2C::sTesterp = new LLImageCompressionTester() ; if (!LLImageJ2C::sTesterp->isValid()) @@ -590,16 +592,23 @@ LLImageJ2CImpl::~LLImageJ2CImpl() //---------------------------------------------------------------------------------------------- // Start of LLImageCompressionTester //---------------------------------------------------------------------------------------------- -LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTesterBasic("ImageCompressionTester") +LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTesterBasic(sTesterName) { + addMetric("TotalTimeDecompression"); addMetric("TotalBytesInDecompression"); addMetric("TotalBytesOutDecompression"); + addMetric("RateDecompression"); + addMetric("PerfDecompression"); + + addMetric("TotalTimeCompression"); addMetric("TotalBytesInCompression"); addMetric("TotalBytesOutCompression"); - - addMetric("TimeTimeDecompression"); - addMetric("TimeTimeCompression"); - + addMetric("RateCompression"); + addMetric("PerfCompression"); + + mRunBytesInDecompression = 0; + mRunBytesInCompression = 0; + mTotalBytesInDecompression = 0; mTotalBytesOutDecompression = 0; mTotalBytesInCompression = 0; @@ -618,13 +627,40 @@ LLImageCompressionTester::~LLImageCompressionTester() void LLImageCompressionTester::outputTestRecord(LLSD *sd) { std::string currentLabel = getCurrentLabelName(); - (*sd)[currentLabel]["TotalBytesInDecompression"] = (LLSD::Integer)mTotalBytesInDecompression; - (*sd)[currentLabel]["TotalBytesOutDecompression"] = (LLSD::Integer)mTotalBytesOutDecompression; - (*sd)[currentLabel]["TotalBytesInCompression"] = (LLSD::Integer)mTotalBytesInCompression; - (*sd)[currentLabel]["TotalBytesOutCompression"] = (LLSD::Integer)mTotalBytesOutCompression; - - (*sd)[currentLabel]["TimeTimeDecompression"] = (LLSD::Real)mTotalTimeDecompression; - (*sd)[currentLabel]["TimeTimeCompression"] = (LLSD::Real)mTotalTimeCompression; + + F32 decompressionPerf = 0.0f; + F32 compressionPerf = 0.0f; + F32 decompressionRate = 0.0f; + F32 compressionRate = 0.0f; + + if (!is_approx_zero(mTotalTimeDecompression)) + { + decompressionPerf = (F32)(mTotalBytesInDecompression) / mTotalTimeDecompression; + } + if (mTotalBytesOutDecompression > 0) + { + decompressionRate = (F32)(mTotalBytesInDecompression) / (F32)(mTotalBytesOutDecompression); + } + if (!is_approx_zero(mTotalTimeCompression)) + { + compressionPerf = (F32)(mTotalBytesInCompression) / mTotalTimeCompression; + } + if (mTotalBytesOutCompression > 0) + { + compressionRate = (F32)(mTotalBytesInCompression) / (F32)(mTotalBytesOutCompression); + } + + (*sd)[currentLabel]["TotalTimeDecompression"] = (LLSD::Real)mTotalTimeDecompression; + (*sd)[currentLabel]["TotalBytesInDecompression"] = (LLSD::Integer)mTotalBytesInDecompression; + (*sd)[currentLabel]["TotalBytesOutDecompression"] = (LLSD::Integer)mTotalBytesOutDecompression; + (*sd)[currentLabel]["RateDecompression"] = (LLSD::Real)decompressionRate; + (*sd)[currentLabel]["PerfDecompression"] = (LLSD::Real)decompressionPerf; + + (*sd)[currentLabel]["TotalTimeCompression"] = (LLSD::Real)mTotalTimeCompression; + (*sd)[currentLabel]["TotalBytesInCompression"] = (LLSD::Integer)mTotalBytesInCompression; + (*sd)[currentLabel]["TotalBytesOutCompression"] = (LLSD::Integer)mTotalBytesOutCompression; + (*sd)[currentLabel]["RateCompression"] = (LLSD::Real)compressionRate; + (*sd)[currentLabel]["PerfCompression"] = (LLSD::Real)compressionPerf; } void LLImageCompressionTester::updateCompressionStats(const F32 deltaTime) @@ -635,15 +671,14 @@ void LLImageCompressionTester::updateCompressionStats(const F32 deltaTime) void LLImageCompressionTester::updateCompressionStats(const S32 bytesCompress, const S32 bytesRaw) { mTotalBytesInCompression += bytesRaw; + mRunBytesInCompression += bytesRaw; mTotalBytesOutCompression += bytesCompress; - if (mTotalBytesInCompression > (1000000)) + if (mRunBytesInCompression > (1000000)) { // Output everything outputTestResults(); - // Reset only the compression data - mTotalBytesInCompression = 0; - mTotalBytesOutCompression = 0; - mTotalTimeCompression = 0.0f; + // Reset the compression data of the run + mRunBytesInCompression = 0; } } @@ -655,15 +690,14 @@ void LLImageCompressionTester::updateDecompressionStats(const F32 deltaTime) void LLImageCompressionTester::updateDecompressionStats(const S32 bytesIn, const S32 bytesOut) { mTotalBytesInDecompression += bytesIn; + mRunBytesInDecompression += bytesIn; mTotalBytesOutDecompression += bytesOut; - if (mTotalBytesInDecompression > (5*1000000)) + if (mRunBytesInDecompression > (1000000)) { // Output everything outputTestResults(); - // Reset only the decompression data - mTotalBytesInDecompression = 0; - mTotalBytesOutDecompression = 0; - mTotalTimeDecompression = 0.0f; + // Reset the decompression data of the run + mRunBytesInDecompression = 0; } } diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index adbfb9cdb3..3933c9236f 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -127,7 +127,7 @@ protected: // // This class is used for performance data gathering only. // Tracks the image compression / decompression data, -// records and outputs them to metric.slp log files. +// records and outputs them to the log file. // class LLImageCompressionTester : public LLMetricPerformanceTesterBasic { @@ -151,6 +151,8 @@ class LLImageCompressionTester : public LLMetricPerformanceTesterBasic U32 mTotalBytesOutDecompression; // Total bytes produced by decompressor U32 mTotalBytesInCompression; // Total bytes fed to compressor U32 mTotalBytesOutCompression; // Total bytes produced by compressor + U32 mRunBytesInDecompression; // Bytes fed to decompressor in this run + U32 mRunBytesInCompression; // Bytes fed to compressor in this run // // Time // diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index 00d69f805e..5ab07af5aa 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -118,6 +118,8 @@ desc Log metrics for benchmarking + count + 1 map-to LogMetrics diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 974ea6b4ae..cfc38f41b9 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -510,16 +510,10 @@ class LLFastTimerLogThread : public LLThread public: std::string mFile; - LLFastTimerLogThread() : LLThread("fast timer log") + LLFastTimerLogThread(std::string& testName) : LLThread("fast timer log") { - if(LLFastTimer::sLog) - { - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"); - } - if(LLFastTimer::sMetricLog) - { - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"); - } + std::string fileName = testName + std::string(".slp"); + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, fileName); } void run() @@ -1616,20 +1610,14 @@ bool LLAppViewer::cleanup() { llinfos << "Analyzing performance" << llendl; - if(LLFastTimer::sLog) - { - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_baseline.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_report.csv")); - } - if(LLFastTimer::sMetricLog) - { - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_baseline.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_report.csv")); - } + std::string baselineName = LLFastTimer::sLogName + "_baseline.slp"; + std::string currentName = LLFastTimer::sLogName + ".slp"; + std::string reportName = LLFastTimer::sLogName + "_report.csv"; + + LLFastTimerView::doAnalysis( + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baselineName), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, currentName), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, reportName)); } LLMetricPerformanceTesterBasic::cleanClass() ; @@ -1738,7 +1726,7 @@ bool LLAppViewer::initThreads() if (LLFastTimer::sLog || LLFastTimer::sMetricLog) { LLFastTimer::sLogLock = new LLMutex(NULL); - mFastTimerLogThread = new LLFastTimerLogThread(); + mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName); mFastTimerLogThread->start(); } @@ -2080,11 +2068,25 @@ bool LLAppViewer::initConfiguration() if (clp.hasOption("logperformance")) { LLFastTimer::sLog = TRUE; + LLFastTimer::sLogName = std::string("performance"); } - if(clp.hasOption("logmetrics")) + if (clp.hasOption("logmetrics")) { LLFastTimer::sMetricLog = TRUE ; + // '--logmetrics' can be specified with a named test metric argument so the data gathering is done only on that test + // In the absence of argument, every metric is gathered (makes for a rather slow run and hard to decipher report...) + std::string testName = clp.getOption("logmetrics")[0]; + llinfos << "'--logmetrics' argument : " << testName << llendl; + if (testName == "") + { + llwarns << "No '--logmetrics' argument given, will output all metrics." << llendl; + LLFastTimer::sLogName = std::string("metric"); + } + else + { + LLFastTimer::sLogName = testName; + } } if (clp.hasOption("graphicslevel")) diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index fdc3b9ef9e..6421f3fd6f 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -167,7 +167,7 @@ public: // mute/unmute the system's master audio virtual void setMasterSystemAudioMute(bool mute); virtual bool getMasterSystemAudioMute(); - + protected: virtual bool initWindow(); // Initialize the viewer's window. virtual bool initLogging(); // Initialize log files, logging system, return false on failure. @@ -251,7 +251,9 @@ private: LLWatchdogTimeout* mMainloopTimeout; + // For performance and metric gathering LLThread* mFastTimerLogThread; + // for tracking viewer<->region circuit death bool mAgentRegionLastAlive; LLUUID mAgentRegionLastID; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 06b145e8c8..5b6a25a041 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -1086,14 +1086,22 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is) //static void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target, std::string output) { + // Open baseline and current target, exit if one is inexistent + std::ifstream base_is(baseline.c_str()); + std::ifstream target_is(target.c_str()); + if (!base_is.is_open() || !target_is.is_open()) + { + llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl; + base_is.close(); + target_is.close(); + return; + } //analyze baseline - std::ifstream base_is(baseline.c_str()); LLSD base = analyzePerformanceLogDefault(base_is); base_is.close(); //analyze current - std::ifstream target_is(target.c_str()); LLSD current = analyzePerformanceLogDefault(target_is); target_is.close(); @@ -1193,13 +1201,22 @@ void LLFastTimerView::doAnalysisMetrics(std::string baseline, std::string target return ; } - //analyze baseline + // Open baseline and current target, exit if one is inexistent std::ifstream base_is(baseline.c_str()); + std::ifstream target_is(target.c_str()); + if (!base_is.is_open() || !target_is.is_open()) + { + llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl; + base_is.close(); + target_is.close(); + return; + } + + //analyze baseline LLSD base = analyzeMetricPerformanceLog(base_is); base_is.close(); //analyze current - std::ifstream target_is(target.c_str()); LLSD current = analyzeMetricPerformanceLog(target_is); target_is.close(); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 537ed7f963..3d047bc2ec 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -72,6 +72,7 @@ LLPointer LLViewerFetchedTexture::sDefaultImagep = NULL; LLPointer LLViewerFetchedTexture::sSmokeImagep = NULL; LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap ; LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL ; +const std::string sTesterName("TextureTester"); S32 LLViewerTexture::sImageCount = 0; S32 LLViewerTexture::sRawCount = 0; @@ -341,7 +342,7 @@ void LLViewerTextureManager::init() LLViewerTexture::initClass() ; - if(LLFastTimer::sMetricLog) + if (LLFastTimer::sMetricLog && !LLViewerTextureManager::sTesterp && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) { LLViewerTextureManager::sTesterp = new LLTexturePipelineTester() ; if (!LLViewerTextureManager::sTesterp->isValid()) @@ -3583,8 +3584,7 @@ F32 LLViewerMediaTexture::getMaxVirtualSize() //---------------------------------------------------------------------------------------------- //start of LLTexturePipelineTester //---------------------------------------------------------------------------------------------- -LLTexturePipelineTester::LLTexturePipelineTester() : - LLMetricPerformanceTesterWithSession("TextureTester") +LLTexturePipelineTester::LLTexturePipelineTester() : LLMetricPerformanceTesterWithSession(sTesterName) { addMetric("TotalBytesLoaded") ; addMetric("TotalBytesLoadedFromCache") ; -- cgit v1.3 From 85509457c6dc6a0f3e56fa3d24ae872e1878c04f Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 5 Nov 2010 18:40:08 -0700 Subject: STORM-105 : Take Vadim code review into account, code clean up --- indra/llcommon/CMakeLists.txt | 4 +- indra/llcommon/llmetricperformancetester.cpp | 142 +++++++++++----------- indra/llcommon/llmetricperformancetester.h | 172 +++++++++++++-------------- indra/llimage/llimagej2c.cpp | 155 ++++++++++++------------ indra/llimage/llimagej2c.h | 8 +- indra/newview/llappviewer.cpp | 30 ++--- indra/newview/llappviewer.h | 4 +- indra/newview/llfasttimerview.cpp | 12 +- indra/newview/llfasttimerview.h | 2 +- indra/newview/llviewertexture.cpp | 40 ++++--- indra/newview/llviewertexture.h | 1 + 11 files changed, 292 insertions(+), 278 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index a6f07f9600..478f2fedbd 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -55,7 +55,6 @@ set(llcommon_SOURCE_FILES llevents.cpp lleventtimer.cpp llfasttimer_class.cpp - llmetricperformancetester.cpp llfile.cpp llfindlocale.cpp llfixedbuffer.cpp @@ -71,6 +70,7 @@ set(llcommon_SOURCE_FILES llmemorystream.cpp llmemtype.cpp llmetrics.cpp + llmetricperformancetester.cpp llmortician.cpp lloptioninterface.cpp llptrto.cpp @@ -161,7 +161,6 @@ set(llcommon_HEADER_FILES llextendedstatus.h llfasttimer.h llfasttimer_class.h - llmetricperformancetester.h llfile.h llfindlocale.h llfixedbuffer.h @@ -188,6 +187,7 @@ set(llcommon_HEADER_FILES llmemorystream.h llmemtype.h llmetrics.h + llmetricperformancetester.h llmortician.h llnametable.h lloptioninterface.h diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp index bd548f199a..2110192fbc 100644 --- a/indra/llcommon/llmetricperformancetester.cpp +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -52,7 +52,7 @@ void LLMetricPerformanceTesterBasic::cleanClass() /*static*/ BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester) { - llassert_always(tester != NULL); + llassert_always(tester != NULL); std::string name = tester->getTesterName() ; if (getTester(name)) { @@ -80,7 +80,7 @@ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::s //---------------------------------------------------------------------------------------------- LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) : - mName(name), + mName(name), mCount(0) { if (mName == std::string()) @@ -110,7 +110,7 @@ void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd) void LLMetricPerformanceTesterBasic::outputTestResults() { LLSD sd; - + preOutputTestResults(&sd) ; outputTestRecord(&sd) ; postOutputTestResults(&sd) ; @@ -124,43 +124,43 @@ void LLMetricPerformanceTesterBasic::addMetric(std::string str) /*virtual*/ void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) { - resetCurrentCount() ; - - std::string currentLabel = getCurrentLabelName(); - BOOL in_base = (*base).has(currentLabel) ; - BOOL in_current = (*current).has(currentLabel) ; - - while(in_base || in_current) - { - LLSD::String label = currentLabel ; - - 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(); - currentLabel = getCurrentLabelName(); - in_base = (*base).has(currentLabel) ; - in_current = (*current).has(currentLabel) ; - } + resetCurrentCount() ; + + std::string currentLabel = getCurrentLabelName(); + BOOL in_base = (*base).has(currentLabel) ; + BOOL in_current = (*current).has(currentLabel) ; + + while(in_base || in_current) + { + LLSD::String label = currentLabel ; + + 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(); + currentLabel = getCurrentLabelName(); + in_base = (*base).has(currentLabel) ; + in_current = (*current).has(currentLabel) ; + } } /*virtual*/ @@ -182,12 +182,12 @@ void LLMetricPerformanceTesterBasic::compareTestResults(std::ofstream* os, std:: //---------------------------------------------------------------------------------------------- LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) : - LLMetricPerformanceTesterBasic(name), - mBaseSessionp(NULL), - mCurrentSessionp(NULL) + LLMetricPerformanceTesterBasic(name), + mBaseSessionp(NULL), + mCurrentSessionp(NULL) { } - + LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession() { if (mBaseSessionp) @@ -205,33 +205,33 @@ LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession() /*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 ; - } + // 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 ; + } } diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h index 82d579b188..6fd1d41daa 100644 --- a/indra/llcommon/llmetricperformancetester.h +++ b/indra/llcommon/llmetricperformancetester.h @@ -35,114 +35,114 @@ class LL_COMMON_API LLMetricPerformanceTesterBasic { public: /** - * @brief Creates a basic tester instance. - * @param[in] name - Unique string identifying this tester instance. - */ + * @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; } + * @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. - */ + * @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. - */ + * @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. - */ + * @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. - */ + * @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. - */ + * @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. - */ + * @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. - */ + * @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. - */ + * @brief Reset internal record count. Count starts with 1. + */ void resetCurrentCount() { mCount = 1; } /** - * @brief Increment internal record count. - */ + * @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. - */ + * @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::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 + // 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. - */ + * @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 there's a tester defined, FALSE otherwise. - */ + * @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 - */ + * @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) ; + // Add a tester to the map. Returns false if adding fails. + static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ; }; /** @@ -153,42 +153,42 @@ class LL_COMMON_API LLMetricPerformanceTesterWithSession : public LLMetricPerfor { public: /** - * @param[in] name - Unique string identifying this tester instance. - */ + * @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() - */ + * @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 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 - */ + /** + * @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 - */ + * @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; }; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 22610817e4..9173a331b3 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -77,8 +77,8 @@ void LLImageJ2C::openDSO() #endif dso_path = gDirUtilp->findFile(dso_name, - gDirUtilp->getAppRODataDir(), - gDirUtilp->getExecutableDir()); + gDirUtilp->getAppRODataDir(), + gDirUtilp->getExecutableDir()); j2cimpl_dso_handle = NULL; j2cimpl_dso_memory_pool = NULL; @@ -108,7 +108,7 @@ void LLImageJ2C::openDSO() //so lets check for a destruction function rv = apr_dso_sym((apr_dso_handle_sym_t*)&dest_func, j2cimpl_dso_handle, - "destroyLLImageJ2CKDU"); + "destroyLLImageJ2CKDU"); if ( rv == APR_SUCCESS ) { //we've loaded the destroy function ok @@ -174,6 +174,12 @@ std::string LLImageJ2C::getEngineInfo() return j2cimpl_engineinfo_func(); } +//static +bool LLImageJ2C::perfStatsEnabled() +{ + return (sTesterp != NULL); +} + LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mMaxBytes(0), mRawDiscardLevel(-1), @@ -202,14 +208,14 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mDataSizes[i] = 0; } - if (LLFastTimer::sMetricLog && !LLImageJ2C::sTesterp && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) + if (LLFastTimer::sMetricLog && !perfStatsEnabled() && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) { - LLImageJ2C::sTesterp = new LLImageCompressionTester() ; - if (!LLImageJ2C::sTesterp->isValid()) - { - delete LLImageJ2C::sTesterp; - LLImageJ2C::sTesterp = NULL; - } + sTesterp = new LLImageCompressionTester() ; + if (!sTesterp->isValid()) + { + delete sTesterp; + sTesterp = NULL; + } } } @@ -296,7 +302,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time) // Returns TRUE to mean done, whether successful or not. BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) { - LLTimer elapsed; + LLTimer elapsed; LLMemType mt1(mMemType); BOOL res = TRUE; @@ -335,19 +341,19 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir LLImage::setLastError(mLastError); } - if (LLImageJ2C::sTesterp) - { - // Decompression stat gathering - // Note that we *do not* take into account the decompression failures data so we night overestimate the time spent processing - - // Always add the decompression time to the stat - LLImageJ2C::sTesterp->updateDecompressionStats(elapsed.getElapsedTimeF32()) ; - if (res) - { - // The whole data stream is finally decompressed when res is returned as TRUE - LLImageJ2C::sTesterp->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; - } - } + if (perfStatsEnabled()) + { + // Decompression stat gathering + // Note that we *do not* take into account the decompression failures data so we might overestimate the time spent processing + + // Always add the decompression time to the stat + sTesterp->updateDecompressionStats(elapsed.getElapsedTimeF32()) ; + if (res) + { + // The whole data stream is finally decompressed when res is returned as TRUE + sTesterp->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; + } + } return res; } @@ -361,7 +367,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time) BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time) { - LLTimer elapsed; + LLTimer elapsed; LLMemType mt1(mMemType); resetLastError(); BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible); @@ -370,21 +376,20 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, LLImage::setLastError(mLastError); } - if (LLImageJ2C::sTesterp) - { - // Compression stat gathering - // Note that we *do not* take into account the compression failures cases so we night overestimate the time spent processing - - // Always add the compression time to the stat - LLImageJ2C::sTesterp->updateCompressionStats(elapsed.getElapsedTimeF32()) ; - if (res) - { - // The whole data stream is finally compressed when res is returned as TRUE - LLImageJ2C::sTesterp->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; - } - } - - + if (perfStatsEnabled()) + { + // Compression stat gathering + // Note that we *do not* take into account the compression failures cases so we night overestimate the time spent processing + + // Always add the compression time to the stat + sTesterp->updateCompressionStats(elapsed.getElapsedTimeF32()) ; + if (res) + { + // The whole data stream is finally compressed when res is returned as TRUE + sTesterp->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; + } + } + return res; } @@ -607,15 +612,15 @@ LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTester addMetric("Perf Compression (kB/s)"); mRunBytesInDecompression = 0; - mRunBytesInCompression = 0; + mRunBytesInCompression = 0; - mTotalBytesInDecompression = 0; - mTotalBytesOutDecompression = 0; - mTotalBytesInCompression = 0; - mTotalBytesOutCompression = 0; + mTotalBytesInDecompression = 0; + mTotalBytesOutDecompression = 0; + mTotalBytesInCompression = 0; + mTotalBytesOutCompression = 0; - mTotalTimeDecompression = 0.0f; - mTotalTimeCompression = 0.0f; + mTotalTimeDecompression = 0.0f; + mTotalTimeCompression = 0.0f; } LLImageCompressionTester::~LLImageCompressionTester() @@ -626,13 +631,13 @@ LLImageCompressionTester::~LLImageCompressionTester() //virtual void LLImageCompressionTester::outputTestRecord(LLSD *sd) { - std::string currentLabel = getCurrentLabelName(); - + std::string currentLabel = getCurrentLabelName(); + F32 decompressionPerf = 0.0f; F32 compressionPerf = 0.0f; F32 decompressionRate = 0.0f; F32 compressionRate = 0.0f; - + F32 totalkBInDecompression = (F32)(mTotalBytesInDecompression) / 1000.0; F32 totalkBOutDecompression = (F32)(mTotalBytesOutDecompression) / 1000.0; F32 totalkBInCompression = (F32)(mTotalBytesInCompression) / 1000.0; @@ -654,56 +659,56 @@ void LLImageCompressionTester::outputTestRecord(LLSD *sd) { compressionRate = totalkBInCompression / totalkBOutCompression; } - + (*sd)[currentLabel]["Time Decompression (s)"] = (LLSD::Real)mTotalTimeDecompression; (*sd)[currentLabel]["Volume In Decompression (kB)"] = (LLSD::Real)totalkBInDecompression; (*sd)[currentLabel]["Volume Out Decompression (kB)"]= (LLSD::Real)totalkBOutDecompression; (*sd)[currentLabel]["Decompression Ratio (x:1)"] = (LLSD::Real)decompressionRate; (*sd)[currentLabel]["Perf Decompression (kB/s)"] = (LLSD::Real)decompressionPerf; - + (*sd)[currentLabel]["Time Compression (s)"] = (LLSD::Real)mTotalTimeCompression; (*sd)[currentLabel]["Volume In Compression (kB)"] = (LLSD::Real)totalkBInCompression; (*sd)[currentLabel]["Volume Out Compression (kB)"] = (LLSD::Real)totalkBOutCompression; - (*sd)[currentLabel]["Compression Ratio (x:1)"] = (LLSD::Real)compressionRate; + (*sd)[currentLabel]["Compression Ratio (x:1)"] = (LLSD::Real)compressionRate; (*sd)[currentLabel]["Perf Compression (kB/s)"] = (LLSD::Real)compressionPerf; } void LLImageCompressionTester::updateCompressionStats(const F32 deltaTime) { - mTotalTimeCompression += deltaTime; + mTotalTimeCompression += deltaTime; } void LLImageCompressionTester::updateCompressionStats(const S32 bytesCompress, const S32 bytesRaw) { - mTotalBytesInCompression += bytesRaw; - mRunBytesInCompression += bytesRaw; - mTotalBytesOutCompression += bytesCompress; - if (mRunBytesInCompression > (1000000)) - { - // Output everything - outputTestResults(); - // Reset the compression data of the run - mRunBytesInCompression = 0; - } + mTotalBytesInCompression += bytesRaw; + mRunBytesInCompression += bytesRaw; + mTotalBytesOutCompression += bytesCompress; + if (mRunBytesInCompression > (1000000)) + { + // Output everything + outputTestResults(); + // Reset the compression data of the run + mRunBytesInCompression = 0; + } } void LLImageCompressionTester::updateDecompressionStats(const F32 deltaTime) { - mTotalTimeDecompression += deltaTime; + mTotalTimeDecompression += deltaTime; } void LLImageCompressionTester::updateDecompressionStats(const S32 bytesIn, const S32 bytesOut) { - mTotalBytesInDecompression += bytesIn; - mRunBytesInDecompression += bytesIn; - mTotalBytesOutDecompression += bytesOut; - if (mRunBytesInDecompression > (1000000)) - { - // Output everything - outputTestResults(); - // Reset the decompression data of the run - mRunBytesInDecompression = 0; - } + mTotalBytesInDecompression += bytesIn; + mRunBytesInDecompression += bytesIn; + mTotalBytesOutDecompression += bytesOut; + if (mRunBytesInDecompression > (1000000)) + { + // Output everything + outputTestResults(); + // Reset the decompression data of the run + mRunBytesInDecompression = 0; + } } //---------------------------------------------------------------------------------------------- diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 3933c9236f..7333f0370f 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -76,13 +76,11 @@ public: static void closeDSO(); static std::string getEngineInfo(); - // Image compression/decompression tester - static LLImageCompressionTester* sTesterp ; - protected: friend class LLImageJ2CImpl; friend class LLImageJ2COJ; friend class LLImageJ2CKDU; + friend class LLImageCompressionTester; void decodeFailed(); void updateRawDiscardLevel(); @@ -96,6 +94,10 @@ protected: BOOL mReversible; LLImageJ2CImpl *mImpl; std::string mLastError; + + // Image compression/decompression tester + static LLImageCompressionTester* sTesterp; + static bool perfStatsEnabled(); }; // Derive from this class to implement JPEG2000 decoding diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 6db9807861..5b69fd80af 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -510,10 +510,10 @@ class LLFastTimerLogThread : public LLThread public: std::string mFile; - LLFastTimerLogThread(std::string& testName) : LLThread("fast timer log") + LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log") { - std::string fileName = testName + std::string(".slp"); - mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, fileName); + std::string file_name = test_name + std::string(".slp"); + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name); } void run() @@ -1303,7 +1303,7 @@ bool LLAppViewer::cleanup() { // workaround for DEV-35406 crash on shutdown LLEventPumps::instance().reset(); - + // remove any old breakpad minidump files from the log directory if (! isError()) { @@ -1641,7 +1641,7 @@ bool LLAppViewer::cleanup() std::string baselineName = LLFastTimer::sLogName + "_baseline.slp"; std::string currentName = LLFastTimer::sLogName + ".slp"; std::string reportName = LLFastTimer::sLogName + "_report.csv"; - + LLFastTimerView::doAnalysis( gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baselineName), gDirUtilp->getExpandedFilename(LL_PATH_LOGS, currentName), @@ -2113,16 +2113,16 @@ bool LLAppViewer::initConfiguration() LLFastTimer::sMetricLog = TRUE ; // '--logmetrics' can be specified with a named test metric argument so the data gathering is done only on that test // In the absence of argument, every metric is gathered (makes for a rather slow run and hard to decipher report...) - std::string testName = clp.getOption("logmetrics")[0]; - llinfos << "'--logmetrics' argument : " << testName << llendl; - if (testName == "") - { - llwarns << "No '--logmetrics' argument given, will output all metrics." << llendl; + std::string test_name = clp.getOption("logmetrics")[0]; + llinfos << "'--logmetrics' argument : " << test_name << llendl; + if (test_name == "") + { + llwarns << "No '--logmetrics' argument given, will output all metrics." << llendl; LLFastTimer::sLogName = std::string("metric"); - } - else - { - LLFastTimer::sLogName = testName; + } + else + { + LLFastTimer::sLogName = test_name; } } @@ -2164,7 +2164,7 @@ bool LLAppViewer::initConfiguration() { LLFastTimerView::sAnalyzePerformance = TRUE; } - + if (clp.hasOption("replaysession")) { LLAgentPilot::sReplaySession = TRUE; diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 3bdc6325c1..a14ab4362f 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -167,7 +167,7 @@ public: // mute/unmute the system's master audio virtual void setMasterSystemAudioMute(bool mute); virtual bool getMasterSystemAudioMute(); - + protected: virtual bool initWindow(); // Initialize the viewer's window. virtual bool initLogging(); // Initialize log files, logging system, return false on failure. @@ -253,7 +253,7 @@ private: // For performance and metric gathering LLThread* mFastTimerLogThread; - + // for tracking viewer<->region circuit death bool mAgentRegionLastAlive; LLUUID mAgentRegionLastID; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 5b6a25a041..92a3b9b2f5 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -1184,12 +1184,12 @@ void LLFastTimerView::outputAllMetrics() { if (LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) { - for (LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin(); - iter != LLMetricPerformanceTesterBasic::sTesterMap.end(); ++iter) - { - LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second); - tester->outputTestResults(); - } + for (LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin(); + iter != LLMetricPerformanceTesterBasic::sTesterMap.end(); ++iter) + { + LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second); + tester->outputTestResults(); + } } } diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h index 1d844454c8..1a54a53f09 100644 --- a/indra/newview/llfasttimerview.h +++ b/indra/newview/llfasttimerview.h @@ -37,7 +37,7 @@ public: static BOOL sAnalyzePerformance; - static void outputAllMetrics(); + static void outputAllMetrics(); static void doAnalysis(std::string baseline, std::string target, std::string output); private: diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index aba52cda4f..2b27f308df 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -288,6 +288,12 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s return gTextureList.getImageFromUrl(url, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id) ; } +//static +bool LLViewerTextureManager::perfStatsEnabled() +{ + return (sTesterp != NULL); +} + LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) { return gTextureList.getImageFromHost(image_id, host) ; @@ -342,14 +348,14 @@ void LLViewerTextureManager::init() LLViewerTexture::initClass() ; - if (LLFastTimer::sMetricLog && !LLViewerTextureManager::sTesterp && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) + if (LLFastTimer::sMetricLog && !perfStatsEnabled() && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) { - LLViewerTextureManager::sTesterp = new LLTexturePipelineTester() ; - if (!LLViewerTextureManager::sTesterp->isValid()) - { - delete LLViewerTextureManager::sTesterp; - LLViewerTextureManager::sTesterp = NULL; - } + sTesterp = new LLTexturePipelineTester() ; + if (!sTesterp->isValid()) + { + delete sTesterp; + sTesterp = NULL; + } } } @@ -414,7 +420,7 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity { sCurrentTime = gFrameTimeSeconds ; - if(LLViewerTextureManager::sTesterp) + if (LLViewerTextureManager::perfStatsEnabled()) { LLViewerTextureManager::sTesterp->update() ; } @@ -609,7 +615,7 @@ bool LLViewerTexture::bindDefaultImage(S32 stage) //check if there is cached raw image and switch to it if possible switchToCachedImage() ; - if(LLViewerTextureManager::sTesterp) + if (LLViewerTextureManager::perfStatsEnabled()) { LLViewerTextureManager::sTesterp->updateGrayTextureBinding() ; } @@ -1072,7 +1078,7 @@ BOOL LLViewerTexture::isLargeImage() //virtual void LLViewerTexture::updateBindStatsForTester() { - if(LLViewerTextureManager::sTesterp) + if (LLViewerTextureManager::perfStatsEnabled()) { LLViewerTextureManager::sTesterp->updateTextureBindingStats(this) ; } @@ -1855,7 +1861,7 @@ bool LLViewerFetchedTexture::updateFetch() // We may have data ready regardless of whether or not we are finished (e.g. waiting on write) if (mRawImage.notNull()) { - if(LLViewerTextureManager::sTesterp) + if (LLViewerTextureManager::perfStatsEnabled()) { mIsFetched = TRUE ; LLViewerTextureManager::sTesterp->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)) ; @@ -3082,7 +3088,7 @@ void LLViewerLODTexture::scaleDown() { switchToCachedImage() ; - if(LLViewerTextureManager::sTesterp) + if (LLViewerTextureManager::perfStatsEnabled()) { LLViewerTextureManager::sTesterp->setStablizingTime() ; } @@ -3621,7 +3627,7 @@ LLTexturePipelineTester::LLTexturePipelineTester() : LLMetricPerformanceTesterWi LLTexturePipelineTester::~LLTexturePipelineTester() { - LLViewerTextureManager::sTesterp = NULL ; + LLViewerTextureManager::sTesterp = NULL; } void LLTexturePipelineTester::update() @@ -3687,7 +3693,7 @@ void LLTexturePipelineTester::reset() //virtual void LLTexturePipelineTester::outputTestRecord(LLSD *sd) { - std::string currentLabel = getCurrentLabelName(); + std::string currentLabel = getCurrentLabelName(); (*sd)[currentLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded ; (*sd)[currentLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache ; (*sd)[currentLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage ; @@ -3874,7 +3880,7 @@ LLMetricPerformanceTesterWithSession::LLTestSession* LLTexturePipelineTester::lo sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ; //load a session - std::string currentLabel = getCurrentLabelName(); + std::string currentLabel = getCurrentLabelName(); BOOL in_log = (*log).has(currentLabel) ; while (in_log) { @@ -3945,9 +3951,9 @@ LLMetricPerformanceTesterWithSession::LLTestSession* LLTexturePipelineTester::lo sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f ; sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ; } - // Next label + // Next label incrementCurrentCount() ; - currentLabel = getCurrentLabelName(); + currentLabel = getCurrentLabelName(); in_log = (*log).has(currentLabel) ; } diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index b5636bbdc7..88d449e061 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -676,6 +676,7 @@ private: public: //texture pipeline tester static LLTexturePipelineTester* sTesterp ; + static bool perfStatsEnabled(); //returns NULL if tex is not a LLViewerFetchedTexture nor derived from LLViewerFetchedTexture. static LLViewerFetchedTexture* staticCastToFetchedTexture(LLTexture* tex, BOOL report_error = FALSE) ; -- cgit v1.3 From b5df1d2abcef04ee5f491a7414189f4e82faaa1e Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 8 Nov 2010 17:16:31 -0800 Subject: STORM-105 : takes Vadim's comments into account, clean up use of static globals and magic strings, enforce naming conventions --- indra/llcommon/llmetricperformancetester.cpp | 23 +++++++++++++------ indra/llcommon/llmetricperformancetester.h | 9 ++++++++ indra/llimage/llimagej2c.cpp | 23 +++++++++---------- indra/llimage/llimagej2c.h | 1 - indra/newview/llappviewer.cpp | 16 +++++++------- indra/newview/llviewertexture.cpp | 33 ++++++++++++++-------------- indra/newview/llviewertexture.h | 1 - 7 files changed, 59 insertions(+), 47 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp index 2110192fbc..5fa3a5ea07 100644 --- a/indra/llcommon/llmetricperformancetester.cpp +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -67,6 +67,7 @@ BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* t /*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()) { @@ -74,6 +75,14 @@ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::s } 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 @@ -126,13 +135,13 @@ void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* { resetCurrentCount() ; - std::string currentLabel = getCurrentLabelName(); - BOOL in_base = (*base).has(currentLabel) ; - BOOL in_current = (*current).has(currentLabel) ; + 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 = currentLabel ; + LLSD::String label = current_label ; if(in_base && in_current) { @@ -157,9 +166,9 @@ void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* } incrementCurrentCount(); - currentLabel = getCurrentLabelName(); - in_base = (*base).has(currentLabel) ; - in_current = (*current).has(currentLabel) ; + current_label = getCurrentLabelName(); + in_base = (*base).has(current_label) ; + in_current = (*current).has(current_label) ; } } diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h index 6fd1d41daa..925010ac96 100644 --- a/indra/llcommon/llmetricperformancetester.h +++ b/indra/llcommon/llmetricperformancetester.h @@ -27,6 +27,8 @@ #ifndef LL_METRICPERFORMANCETESTER_H #define LL_METRICPERFORMANCETESTER_H +const std::string DEFAULT_METRIC_NAME("metric"); + /** * @class LLMetricPerformanceTesterBasic * @brief Performance Metric Base Class @@ -131,6 +133,13 @@ public: * @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. */ diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 9173a331b3..d005aaf29f 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -174,12 +174,6 @@ std::string LLImageJ2C::getEngineInfo() return j2cimpl_engineinfo_func(); } -//static -bool LLImageJ2C::perfStatsEnabled() -{ - return (sTesterp != NULL); -} - LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mMaxBytes(0), mRawDiscardLevel(-1), @@ -208,7 +202,8 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mDataSizes[i] = 0; } - if (LLFastTimer::sMetricLog && !perfStatsEnabled() && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) + // If that test log has ben requested but not yet created, create it + if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName)) { sTesterp = new LLImageCompressionTester() ; if (!sTesterp->isValid()) @@ -341,17 +336,18 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir LLImage::setLastError(mLastError); } - if (perfStatsEnabled()) + LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) { // Decompression stat gathering // Note that we *do not* take into account the decompression failures data so we might overestimate the time spent processing // Always add the decompression time to the stat - sTesterp->updateDecompressionStats(elapsed.getElapsedTimeF32()) ; + tester->updateDecompressionStats(elapsed.getElapsedTimeF32()) ; if (res) { // The whole data stream is finally decompressed when res is returned as TRUE - sTesterp->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; + tester->updateDecompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; } } @@ -376,17 +372,18 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, LLImage::setLastError(mLastError); } - if (perfStatsEnabled()) + LLImageCompressionTester* tester = (LLImageCompressionTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) { // Compression stat gathering // Note that we *do not* take into account the compression failures cases so we night overestimate the time spent processing // Always add the compression time to the stat - sTesterp->updateCompressionStats(elapsed.getElapsedTimeF32()) ; + tester->updateCompressionStats(elapsed.getElapsedTimeF32()) ; if (res) { // The whole data stream is finally compressed when res is returned as TRUE - sTesterp->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; + tester->updateCompressionStats(this->getDataSize(), raw_imagep->getDataSize()) ; } } diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 7333f0370f..cc3dabd7d8 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -97,7 +97,6 @@ protected: // Image compression/decompression tester static LLImageCompressionTester* sTesterp; - static bool perfStatsEnabled(); }; // Derive from this class to implement JPEG2000 decoding diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 5b69fd80af..bf0f948a6d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1638,14 +1638,14 @@ bool LLAppViewer::cleanup() { llinfos << "Analyzing performance" << llendl; - std::string baselineName = LLFastTimer::sLogName + "_baseline.slp"; - std::string currentName = LLFastTimer::sLogName + ".slp"; - std::string reportName = LLFastTimer::sLogName + "_report.csv"; + std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp"; + std::string current_name = LLFastTimer::sLogName + ".slp"; + std::string report_name = LLFastTimer::sLogName + "_report.csv"; LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baselineName), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, currentName), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, reportName)); + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); } LLMetricPerformanceTesterBasic::cleanClass() ; @@ -2117,8 +2117,8 @@ bool LLAppViewer::initConfiguration() llinfos << "'--logmetrics' argument : " << test_name << llendl; if (test_name == "") { - llwarns << "No '--logmetrics' argument given, will output all metrics." << llendl; - LLFastTimer::sLogName = std::string("metric"); + llwarns << "No '--logmetrics' argument given, will output all metrics to " << DEFAULT_METRIC_NAME << llendl; + LLFastTimer::sLogName = DEFAULT_METRIC_NAME; } else { diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 2b27f308df..6160510c0e 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -288,12 +288,6 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const s return gTextureList.getImageFromUrl(url, usemipmaps, boost_priority, texture_type, internal_format, primary_format, force_id) ; } -//static -bool LLViewerTextureManager::perfStatsEnabled() -{ - return (sTesterp != NULL); -} - LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) { return gTextureList.getImageFromHost(image_id, host) ; @@ -348,7 +342,7 @@ void LLViewerTextureManager::init() LLViewerTexture::initClass() ; - if (LLFastTimer::sMetricLog && !perfStatsEnabled() && ((LLFastTimer::sLogName == sTesterName) || (LLFastTimer::sLogName == "metric"))) + if (LLMetricPerformanceTesterBasic::isMetricLogRequested(sTesterName) && !LLMetricPerformanceTesterBasic::getTester(sTesterName)) { sTesterp = new LLTexturePipelineTester() ; if (!sTesterp->isValid()) @@ -420,9 +414,10 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity { sCurrentTime = gFrameTimeSeconds ; - if (LLViewerTextureManager::perfStatsEnabled()) + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) { - LLViewerTextureManager::sTesterp->update() ; + tester->update() ; } LLViewerMediaTexture::updateClass() ; @@ -615,9 +610,10 @@ bool LLViewerTexture::bindDefaultImage(S32 stage) //check if there is cached raw image and switch to it if possible switchToCachedImage() ; - if (LLViewerTextureManager::perfStatsEnabled()) + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) { - LLViewerTextureManager::sTesterp->updateGrayTextureBinding() ; + tester->updateGrayTextureBinding() ; } return res; } @@ -1078,9 +1074,10 @@ BOOL LLViewerTexture::isLargeImage() //virtual void LLViewerTexture::updateBindStatsForTester() { - if (LLViewerTextureManager::perfStatsEnabled()) + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) { - LLViewerTextureManager::sTesterp->updateTextureBindingStats(this) ; + tester->updateTextureBindingStats(this) ; } } @@ -1861,10 +1858,11 @@ bool LLViewerFetchedTexture::updateFetch() // We may have data ready regardless of whether or not we are finished (e.g. waiting on write) if (mRawImage.notNull()) { - if (LLViewerTextureManager::perfStatsEnabled()) + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) { mIsFetched = TRUE ; - LLViewerTextureManager::sTesterp->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)) ; + tester->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)) ; } mRawDiscardLevel = fetch_discard; if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) && @@ -3088,9 +3086,10 @@ void LLViewerLODTexture::scaleDown() { switchToCachedImage() ; - if (LLViewerTextureManager::perfStatsEnabled()) + LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); + if (tester) { - LLViewerTextureManager::sTesterp->setStablizingTime() ; + tester->setStablizingTime() ; } } } diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 88d449e061..b5636bbdc7 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -676,7 +676,6 @@ private: public: //texture pipeline tester static LLTexturePipelineTester* sTesterp ; - static bool perfStatsEnabled(); //returns NULL if tex is not a LLViewerFetchedTexture nor derived from LLViewerFetchedTexture. static LLViewerFetchedTexture* staticCastToFetchedTexture(LLTexture* tex, BOOL report_error = FALSE) ; -- cgit v1.3 From b2fcba25c8dd04318420af30f877b0984a524055 Mon Sep 17 00:00:00 2001 From: Vadim ProductEngine Date: Sat, 13 Nov 2010 00:53:29 +0200 Subject: STORM-52 FIXED Made it possible to use an external script editor. The editor can be specified: * via "ExternalEditor" setting in settings.xml * via LL_SCRIPT_EDITOR variable Removed obsolete XUIEditor setting in favor of the new one. --- indra/llcommon/llprocesslauncher.cpp | 5 + indra/llcommon/llprocesslauncher.h | 2 + indra/newview/CMakeLists.txt | 2 + indra/newview/app_settings/settings.xml | 4 +- indra/newview/llexternaleditor.cpp | 192 +++++++++++++++++ indra/newview/llexternaleditor.h | 91 ++++++++ indra/newview/llfloateruipreview.cpp | 210 ++++-------------- indra/newview/llpreviewscript.cpp | 235 ++++++++++++++++----- indra/newview/llpreviewscript.h | 15 +- .../skins/default/xui/en/panel_script_ed.xml | 9 + 10 files changed, 537 insertions(+), 228 deletions(-) create mode 100644 indra/newview/llexternaleditor.cpp create mode 100644 indra/newview/llexternaleditor.h (limited to 'indra/llcommon') diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp index 99308c94e7..81e5f8820d 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(); 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/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 09622d3af5..d44b0ce679 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -143,6 +143,7 @@ set(viewer_SOURCE_FILES lleventnotifier.cpp lleventpoll.cpp llexpandabletextbox.cpp + llexternaleditor.cpp llface.cpp llfasttimerview.cpp llfavoritesbar.cpp @@ -674,6 +675,7 @@ set(viewer_HEADER_FILES lleventnotifier.h lleventpoll.h llexpandabletextbox.h + llexternaleditor.h llface.h llfasttimerview.h llfavoritesbar.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index ebd93b5987..a5d9bd0f4f 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11883,10 +11883,10 @@ Value 150000.0 - XUIEditor + ExternalEditor Comment - Path to program used to edit XUI files + Path to program used to edit LSL scripts and XUI files, e.g.: /usr/bin/gedit --new-window "%s" Persist 1 Type diff --git a/indra/newview/llexternaleditor.cpp b/indra/newview/llexternaleditor.cpp new file mode 100644 index 0000000000..54968841ab --- /dev/null +++ b/indra/newview/llexternaleditor.cpp @@ -0,0 +1,192 @@ +/** + * @file llexternaleditor.cpp + * @brief A convenient class to run external editor. + * + * $LicenseInfo:firstyear=2010&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 "llviewerprecompiledheaders.h" +#include "llexternaleditor.h" + +#include "llui.h" + +// static +const std::string LLExternalEditor::sFilenameMarker = "%s"; + +// static +const std::string LLExternalEditor::sSetting = "ExternalEditor"; + +bool LLExternalEditor::setCommand(const std::string& env_var, const std::string& override) +{ + std::string cmd = findCommand(env_var, override); + if (cmd.empty()) + { + llwarns << "Empty editor command" << llendl; + return false; + } + + // Add the filename marker if missing. + if (cmd.find(sFilenameMarker) == std::string::npos) + { + cmd += " \"" + sFilenameMarker + "\""; + llinfos << "Adding the filename marker (" << sFilenameMarker << ")" << llendl; + } + + string_vec_t tokens; + if (tokenize(tokens, cmd) < 2) // 2 = bin + at least one arg (%s) + { + llwarns << "Error parsing editor command" << llendl; + return false; + } + + // Check executable for existence. + std::string bin_path = tokens[0]; + if (!LLFile::isfile(bin_path)) + { + llwarns << "Editor binary [" << bin_path << "] not found" << llendl; + return false; + } + + // Save command. + mProcess.setExecutable(bin_path); + mArgs.clear(); + for (size_t i = 1; i < tokens.size(); ++i) + { + if (i > 1) mArgs += " "; + mArgs += "\"" + tokens[i] + "\""; + } + llinfos << "Setting command [" << bin_path << " " << mArgs << "]" << llendl; + + return true; +} + +bool LLExternalEditor::run(const std::string& file_path) +{ + std::string args = mArgs; + if (mProcess.getExecutable().empty() || args.empty()) + { + llwarns << "Editor command not set" << llendl; + return false; + } + + // Substitute the filename marker in the command with the actual passed file name. + LLStringUtil::replaceString(args, sFilenameMarker, file_path); + + // Split command into separate tokens. + string_vec_t tokens; + tokenize(tokens, args); + + // Set process arguments taken from the command. + mProcess.clearArguments(); + for (string_vec_t::const_iterator arg_it = tokens.begin(); arg_it != tokens.end(); ++arg_it) + { + mProcess.addArgument(*arg_it); + } + + // Run the editor. + llinfos << "Running editor command [" << mProcess.getExecutable() + " " + args << "]" << llendl; + int result = mProcess.launch(); + if (result == 0) + { + // Prevent killing the process in destructor (will add it to the zombies list). + mProcess.orphan(); + } + + return result == 0; +} + +// static +size_t LLExternalEditor::tokenize(string_vec_t& tokens, const std::string& str) +{ + tokens.clear(); + + // Split the argument string into separate strings for each argument + typedef boost::tokenizer< boost::char_separator > tokenizer; + boost::char_separator sep("", "\" ", boost::drop_empty_tokens); + + tokenizer tokens_list(str, sep); + tokenizer::iterator token_iter; + BOOL inside_quotes = FALSE; + BOOL last_was_space = FALSE; + for (token_iter = tokens_list.begin(); token_iter != tokens_list.end(); ++token_iter) + { + if (!strncmp("\"",(*token_iter).c_str(),2)) + { + inside_quotes = !inside_quotes; + } + else if (!strncmp(" ",(*token_iter).c_str(),2)) + { + if(inside_quotes) + { + tokens.back().append(std::string(" ")); + last_was_space = TRUE; + } + } + else + { + std::string to_push = *token_iter; + if (last_was_space) + { + tokens.back().append(to_push); + last_was_space = FALSE; + } + else + { + tokens.push_back(to_push); + } + } + } + + return tokens.size(); +} + +// static +std::string LLExternalEditor::findCommand( + const std::string& env_var, + const std::string& override) +{ + std::string cmd; + + // Get executable path. + if (!override.empty()) // try the supplied override first + { + cmd = override; + llinfos << "Using override" << llendl; + } + else if (!LLUI::sSettingGroups["config"]->getString(sSetting).empty()) + { + cmd = LLUI::sSettingGroups["config"]->getString(sSetting); + llinfos << "Using setting" << llendl; + } + else // otherwise use the path specified by the environment variable + { + char* env_var_val = getenv(env_var.c_str()); + if (env_var_val) + { + cmd = env_var_val; + llinfos << "Using env var " << env_var << llendl; + } + } + + llinfos << "Found command [" << cmd << "]" << llendl; + return cmd; +} diff --git a/indra/newview/llexternaleditor.h b/indra/newview/llexternaleditor.h new file mode 100644 index 0000000000..6ea210d5e2 --- /dev/null +++ b/indra/newview/llexternaleditor.h @@ -0,0 +1,91 @@ +/** + * @file llexternaleditor.h + * @brief A convenient class to run external editor. + * + * $LicenseInfo:firstyear=2010&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_LLEXTERNALEDITOR_H +#define LL_LLEXTERNALEDITOR_H + +#include + +/** + * Usage: + * LLExternalEditor ed; + * ed.setCommand("MY_EXTERNAL_EDITOR_VAR"); + * ed.run("/path/to/file1"); + * ed.run("/other/path/to/file2"); + */ +class LLExternalEditor +{ + typedef std::vector string_vec_t; + +public: + + /** + * Set editor command. + * + * @param env_var Environment variable of the same purpose. + * @param override Optional override. + * + * First tries the override, then a predefined setting (sSetting), + * then the environment variable. + * + * @return Command if found, empty string otherwise. + * + * @see sSetting + */ + bool setCommand(const std::string& env_var, const std::string& override = LLStringUtil::null); + + /** + * Run the editor with the given file. + * + * @param file_path File to edit. + * @return true on success, false on error. + */ + bool run(const std::string& file_path); + +private: + + static std::string findCommand( + const std::string& env_var, + const std::string& override); + + static size_t tokenize(string_vec_t& tokens, const std::string& str); + + /** + * Filename placeholder that gets replaced with an actual file name. + */ + static const std::string sFilenameMarker; + + /** + * Setting that can specify the editor command. + */ + static const std::string sSetting; + + + std::string mArgs; + LLProcessLauncher mProcess; +}; + +#endif // LL_LLEXTERNALEDITOR_H diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp index 5dc8067648..d3a2f144d9 100644 --- a/indra/newview/llfloateruipreview.cpp +++ b/indra/newview/llfloateruipreview.cpp @@ -36,6 +36,7 @@ // Internal utility #include "lleventtimer.h" +#include "llexternaleditor.h" #include "llrender.h" #include "llsdutil.h" #include "llxmltree.h" @@ -160,6 +161,8 @@ public: DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors private: + LLExternalEditor mExternalEditor; + // XUI elements for this floater LLScrollListCtrl* mFileList; // scroll list control for file list LLLineEditor* mEditorPathTextBox; // text field for path to editor executable @@ -185,7 +188,7 @@ private: std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it // Internal functionality - static void popupAndPrintWarning(std::string& warning); // pop up a warning + static void popupAndPrintWarning(const std::string& warning); // pop up a warning std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater @@ -597,7 +600,7 @@ void LLFloaterUIPreview::onClose(bool app_quitting) // Error handling (to avoid code repetition) // *TODO: this is currently unlocalized. Add to alerts/notifications.xml, someday, maybe. -void LLFloaterUIPreview::popupAndPrintWarning(std::string& warning) +void LLFloaterUIPreview::popupAndPrintWarning(const std::string& warning) { llwarns << warning << llendl; LLSD args; @@ -998,190 +1001,55 @@ void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save) // Respond to button click to edit currently-selected floater void LLFloaterUIPreview::onClickEditFloater() { - std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater - if(std::string("") == file_name) // if no item is selected - { - return; // ignore click - } - std::string path = getLocalizedDirectory() + file_name; - - // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) - llstat dummy; - if(LLFile::stat(path.c_str(), &dummy)) // if the file does not exist - { - std::string warning = "No file for this floater exists in the selected localization. Opening the EN version instead."; - popupAndPrintWarning(warning); - - path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default - } - - // get executable path - const char* exe_path_char; - std::string path_in_textfield = mEditorPathTextBox->getText(); - if(std::string("") != path_in_textfield) // if the text field is not emtpy, use its path - { - exe_path_char = path_in_textfield.c_str(); - } - else if (!LLUI::sSettingGroups["config"]->getString("XUIEditor").empty()) - { - exe_path_char = LLUI::sSettingGroups["config"]->getString("XUIEditor").c_str(); - } - else // otherwise use the path specified by the environment variable + // Determine file to edit. + std::string file_path; { - exe_path_char = getenv("LL_XUI_EDITOR"); - } - - // error check executable path - if(NULL == exe_path_char) - { - std::string warning = "Select an editor by setting the environment variable LL_XUI_EDITOR or specifying its path in the \"Editor Path\" field."; - popupAndPrintWarning(warning); - return; - } - std::string exe_path = exe_path_char; // do this after error check, otherwise internal strlen call fails on bad char* - - // remove any quotes; they're added back in later where necessary - int found_at; - while((found_at = exe_path.find("\"")) != -1 || (found_at = exe_path.find("'")) != -1) - { - exe_path.erase(found_at,1); - } - - llstat s; - if(!LLFile::stat(exe_path.c_str(), &s)) // If the executable exists - { - // build paths and arguments - std::string quote = std::string("\""); - std::string args; - std::string custom_args = mEditorArgsTextBox->getText(); - int position_of_file = custom_args.find(std::string("%FILE%"), 0); // prepare to replace %FILE% with actual file path - std::string first_part_of_args = ""; - std::string second_part_of_args = ""; - if(-1 == position_of_file) // default: Executable.exe File.xml - { - args = quote + path + quote; // execute the command Program.exe "File.xml" - } - else // use advanced command-line arguments, e.g. "Program.exe -safe File.xml" -windowed for "-safe %FILE% -windowed" + std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater + if (file_name.empty()) // if no item is selected { - first_part_of_args = custom_args.substr(0,position_of_file); // get part of args before file name - second_part_of_args = custom_args.substr(position_of_file+6,custom_args.length()); // get part of args after file name - custom_args = first_part_of_args + std::string("\"") + path + std::string("\"") + second_part_of_args; // replace %FILE% with "" and put back together - args = custom_args; // and save in the variable that is actually used + llwarns << "No file selected" << llendl; + return; // ignore click } + file_path = getLocalizedDirectory() + file_name; - // find directory in which executable resides by taking everything after last slash - int last_slash_position = exe_path.find_last_of(mDelim); - if(-1 == last_slash_position) - { - std::string warning = std::string("Unable to find a valid path to the specified executable for XUI XML editing: ") + exe_path; - popupAndPrintWarning(warning); - return; - } - std::string exe_dir = exe_path.substr(0,last_slash_position); // strip executable off, e.g. get "C:\Program Files\TextPad 5" (with or without trailing slash) - -#if LL_WINDOWS - PROCESS_INFORMATION pinfo; - STARTUPINFOA sinfo; - memset(&sinfo, 0, sizeof(sinfo)); - memset(&pinfo, 0, sizeof(pinfo)); - - std::string exe_name = exe_path.substr(last_slash_position+1); - args = quote + exe_name + quote + std::string(" ") + args; // and prepend the executable name, so we get 'Program.exe "Arg1"' - - char *args2 = new char[args.size() + 1]; // Windows requires that the second parameter to CreateProcessA be a writable (non-const) string... - strcpy(args2, args.c_str()); - - // we don't want the current directory to be the executable directory, since the file path is now relative. By using - // NULL for the current directory instead of exe_dir.c_str(), the path to the target file will work. - if(!CreateProcessA(exe_path.c_str(), args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) - { - // DWORD dwErr = GetLastError(); - std::string warning = "Creating editor process failed!"; - popupAndPrintWarning(warning); - } - else + // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) + llstat dummy; + if(LLFile::stat(file_path.c_str(), &dummy)) // if the file does not exist { - // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on - // sGatewayHandle = pinfo.hProcess; - CloseHandle(pinfo.hThread); // stops leaks - nothing else + popupAndPrintWarning("No file for this floater exists in the selected localization. Opening the EN version instead."); + file_path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default } + } - delete[] args2; -#else // if !LL_WINDOWS - // This code was copied from the code to run SLVoice, with some modification; should work in UNIX (Mac/Darwin or Linux) + // Set the editor command. + std::string cmd_override; + { + std::string bin = mEditorPathTextBox->getText(); + if (!bin.empty()) { - std::vector arglist; - arglist.push_back(exe_path.c_str()); - - // Split the argument string into separate strings for each argument - typedef boost::tokenizer< boost::char_separator > tokenizer; - boost::char_separator sep("","\" ", boost::drop_empty_tokens); - - tokenizer tokens(args, sep); - tokenizer::iterator token_iter; - BOOL inside_quotes = FALSE; - BOOL last_was_space = FALSE; - for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - if(!strncmp("\"",(*token_iter).c_str(),2)) - { - inside_quotes = !inside_quotes; - } - else if(!strncmp(" ",(*token_iter).c_str(),2)) - { - if(inside_quotes) - { - arglist.back().append(std::string(" ")); - last_was_space = TRUE; - } - } - else - { - std::string to_push = *token_iter; - if(last_was_space) - { - arglist.back().append(to_push); - last_was_space = FALSE; - } - else - { - arglist.push_back(to_push); - } - } - } - - // create an argv vector for the child process - char **fakeargv = new char*[arglist.size() + 1]; - int i; - for(i=0; i < arglist.size(); i++) - fakeargv[i] = const_cast(arglist[i].c_str()); - - fakeargv[i] = NULL; - - fflush(NULL); // flush all buffers before the child inherits them - pid_t id = vfork(); - if(id == 0) + // surround command with double quotes for the case if the path contains spaces + if (bin.find("\"") == std::string::npos) { - // child - execv(exe_path.c_str(), fakeargv); - - // If we reach this point, the exec failed. - // Use _exit() instead of exit() per the vfork man page. - std::string warning = "Creating editor process failed (vfork/execv)!"; - popupAndPrintWarning(warning); - _exit(0); + bin = "\"" + bin + "\""; } - // parent - delete[] fakeargv; - // sGatewayPID = id; + std::string args = mEditorArgsTextBox->getText(); + cmd_override = bin + " " + args; } -#endif // LL_WINDOWS } - else + if (!mExternalEditor.setCommand("LL_XUI_EDITOR", cmd_override)) { - std::string warning = "Unable to find path to external XML editor for XUI preview tool"; + std::string warning = "Select an editor by setting the environment variable LL_XUI_EDITOR " + "or the ExternalEditor setting or specifying its path in the \"Editor Path\" field."; popupAndPrintWarning(warning); + return; + } + + // Run the editor. + if (!mExternalEditor.run(file_path)) + { + popupAndPrintWarning("Failed to run editor"); + return; } } diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index cf2ea38288..330e809c53 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -34,11 +34,13 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldir.h" +#include "llexternaleditor.h" #include "llfloaterreg.h" #include "llinventorydefines.h" #include "llinventorymodel.h" #include "llkeyboard.h" #include "lllineeditor.h" +#include "lllivefile.h" #include "llhelp.h" #include "llnotificationsutil.h" #include "llresmgr.h" @@ -115,6 +117,54 @@ static bool have_script_upload_cap(LLUUID& object_id) return object && (! object->getRegion()->getCapability("UpdateScriptTask").empty()); } +/// --------------------------------------------------------------------------- +/// LLLiveLSLFile +/// --------------------------------------------------------------------------- +class LLLiveLSLFile : public LLLiveFile +{ +public: + LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent); + ~LLLiveLSLFile(); + + void ignoreNextUpdate() { mIgnoreNextUpdate = true; } + +protected: + /*virtual*/ bool loadFile(); + + LLLiveLSLEditor* mParent; + bool mIgnoreNextUpdate; +}; + +LLLiveLSLFile::LLLiveLSLFile(std::string file_path, LLLiveLSLEditor* parent) +: mParent(parent) +, mIgnoreNextUpdate(false) +, LLLiveFile(file_path, 1.0) +{ +} + +LLLiveLSLFile::~LLLiveLSLFile() +{ + LLFile::remove(filename()); +} + +bool LLLiveLSLFile::loadFile() +{ + if (mIgnoreNextUpdate) + { + mIgnoreNextUpdate = false; + return true; + } + + if (!mParent->loadScriptText(filename())) + { + return false; + } + + // Disable sync to avoid recursive load->save->load calls. + mParent->saveIfNeeded(false); + return true; +} + /// --------------------------------------------------------------------------- /// LLFloaterScriptSearch /// --------------------------------------------------------------------------- @@ -281,6 +331,7 @@ LLScriptEdCore::LLScriptEdCore( const LLHandle& floater_handle, void (*load_callback)(void*), void (*save_callback)(void*, BOOL), + void (*edit_callback)(void*), void (*search_replace_callback) (void* userdata), void* userdata, S32 bottom_pad) @@ -290,6 +341,7 @@ LLScriptEdCore::LLScriptEdCore( mEditor( NULL ), mLoadCallback( load_callback ), mSaveCallback( save_callback ), + mEditCallback( edit_callback ), mSearchReplaceCallback( search_replace_callback ), mUserdata( userdata ), mForceClose( FALSE ), @@ -329,6 +381,7 @@ BOOL LLScriptEdCore::postBuild() childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this); childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE)); + childSetAction("Edit_btn", boost::bind(&LLScriptEdCore::onEditButtonClick, this)); initMenu(); @@ -809,6 +862,13 @@ void LLScriptEdCore::doSave( BOOL close_after_save ) } } +void LLScriptEdCore::onEditButtonClick() +{ + if (mEditCallback) + { + mEditCallback(mUserdata); + } +} void LLScriptEdCore::onBtnUndoChanges() { @@ -949,6 +1009,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) self->getHandle(), LLPreviewLSL::onLoad, LLPreviewLSL::onSave, + NULL, // no edit callback LLPreviewLSL::onSearchReplace, self, 0); @@ -1417,6 +1478,7 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) self->getHandle(), &LLLiveLSLEditor::onLoad, &LLLiveLSLEditor::onSave, + &LLLiveLSLEditor::onEdit, &LLLiveLSLEditor::onSearchReplace, self, 0); @@ -1433,6 +1495,7 @@ LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) : mCloseAfterSave(FALSE), mPendingUploads(0), mIsModifiable(FALSE), + mLiveFile(NULL), mIsNew(false) { mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); @@ -1458,6 +1521,7 @@ BOOL LLLiveLSLEditor::postBuild() LLLiveLSLEditor::~LLLiveLSLEditor() { + delete mLiveFile; } // virtual @@ -1639,38 +1703,39 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, delete xored_id; } -// unused -// void LLLiveLSLEditor::loadScriptText(const std::string& filename) -// { -// if(!filename) -// { -// llerrs << "Filename is Empty!" << llendl; -// return; -// } -// LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ -// if(file) -// { -// // read in the whole file -// fseek(file, 0L, SEEK_END); -// long file_length = ftell(file); -// fseek(file, 0L, SEEK_SET); -// char* buffer = new char[file_length+1]; -// size_t nread = fread(buffer, 1, file_length, file); -// if (nread < (size_t) file_length) -// { -// llwarns << "Short read" << llendl; -// } -// buffer[nread] = '\0'; -// fclose(file); -// mScriptEd->mEditor->setText(LLStringExplicit(buffer)); -// mScriptEd->mEditor->makePristine(); -// delete[] buffer; -// } -// else -// { -// llwarns << "Error opening " << filename << llendl; -// } -// } + bool LLLiveLSLEditor::loadScriptText(const std::string& filename) + { + if (filename.empty()) + { + llwarns << "Empty file name" << llendl; + return false; + } + + LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/ + if (!file) + { + llwarns << "Error opening " << filename << llendl; + return false; + } + + // read in the whole file + fseek(file, 0L, SEEK_END); + size_t file_length = (size_t) ftell(file); + fseek(file, 0L, SEEK_SET); + char* buffer = new char[file_length+1]; + size_t nread = fread(buffer, 1, file_length, file); + if (nread < file_length) + { + llwarns << "Short read" << llendl; + } + buffer[nread] = '\0'; + fclose(file); + mScriptEd->mEditor->setText(LLStringExplicit(buffer)); + //mScriptEd->mEditor->makePristine(); + delete[] buffer; + + return true; + } void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type) { @@ -1825,9 +1890,8 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id, mItem = new LLViewerInventoryItem(item); } -void LLLiveLSLEditor::saveIfNeeded() +void LLLiveLSLEditor::saveIfNeeded(bool sync) { - llinfos << "LLLiveLSLEditor::saveIfNeeded()" << llendl; LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(!object) { @@ -1877,9 +1941,74 @@ void LLLiveLSLEditor::saveIfNeeded() mItem->setAssetUUID(asset_id); mItem->setTransactionID(tid); - // write out the data, and store it in the asset database + writeToFile(filename); + + if (sync) + { + // Sync with external ed2itor. + std::string tmp_file = getTmpFileName(); + llstat s; + if (LLFile::stat(tmp_file, &s) == 0) // file exists + { + if (mLiveFile) mLiveFile->ignoreNextUpdate(); + writeToFile(tmp_file); + } + } + + // save it out to asset server + std::string url = object->getRegion()->getCapability("UpdateScriptTask"); + getWindow()->incBusyCount(); + mPendingUploads++; + BOOL is_running = getChild( "running")->get(); + if (!url.empty()) + { + uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running); + } + else if (gAssetStorage) + { + uploadAssetLegacy(filename, object, tid, is_running); + } +} + +void LLLiveLSLEditor::openExternalEditor() +{ + LLViewerObject* object = gObjectList.findObject(mObjectUUID); + if(!object) + { + LLNotificationsUtil::add("SaveScriptFailObjectNotFound"); + return; + } + + delete mLiveFile; // deletes file + + // Save the script to a temporary file. + std::string filename = getTmpFileName(); + writeToFile(filename); + + // Start watching file changes. + mLiveFile = new LLLiveLSLFile(filename, this); + mLiveFile->addToEventTimer(); + + // Open it in external editor. + { + LLExternalEditor ed; + + if (!ed.setCommand("LL_SCRIPT_EDITOR")) + { + std::string msg = "Select an editor by setting the environment variable LL_SCRIPT_EDITOR " + "or the ExternalEditor setting"; // *TODO: localize + LLNotificationsUtil::add("GenericAlert", LLSD().with("MESSAGE", msg)); + return; + } + + ed.run(filename); + } +} + +bool LLLiveLSLEditor::writeToFile(const std::string& filename) +{ LLFILE* fp = LLFile::fopen(filename, "wb"); - if(!fp) + if (!fp) { llwarns << "Unable to write to " << filename << llendl; @@ -1887,33 +2016,25 @@ void LLLiveLSLEditor::saveIfNeeded() row["columns"][0]["value"] = "Error writing to local file. Is your hard drive full?"; row["columns"][0]["font"] = "SANSSERIF_SMALL"; mScriptEd->mErrorList->addElement(row); - return; + return false; } + std::string utf8text = mScriptEd->mEditor->getText(); // Special case for a completely empty script - stuff in one space so it can store properly. See SL-46889 - if ( utf8text.size() == 0 ) + if (utf8text.size() == 0) { utf8text = " "; } fputs(utf8text.c_str(), fp); fclose(fp); - fp = NULL; - - // save it out to asset server - std::string url = object->getRegion()->getCapability("UpdateScriptTask"); - getWindow()->incBusyCount(); - mPendingUploads++; - BOOL is_running = getChild( "running")->get(); - if (!url.empty()) - { - uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running); - } - else if (gAssetStorage) - { - uploadAssetLegacy(filename, object, tid, is_running); - } + return true; +} + +std::string LLLiveLSLEditor::getTmpFileName() +{ + return std::string(LLFile::tmpdir()) + "sl_script_" + mObjectUUID.asString() + ".lsl"; } void LLLiveLSLEditor::uploadAssetViaCaps(const std::string& url, @@ -2138,6 +2259,14 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) self->saveIfNeeded(); } + +// static +void LLLiveLSLEditor::onEdit(void* userdata) +{ + LLLiveLSLEditor* self = (LLLiveLSLEditor*)userdata; + self->openExternalEditor(); +} + // static void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) { diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index f4b31e5962..d35c6b8528 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -35,6 +35,7 @@ #include "lliconctrl.h" #include "llframetimer.h" +class LLLiveLSLFile; class LLMessageSystem; class LLTextEditor; class LLButton; @@ -62,6 +63,7 @@ public: const LLHandle& floater_handle, void (*load_callback)(void* userdata), void (*save_callback)(void* userdata, BOOL close_after_save), + void (*edit_callback)(void*), void (*search_replace_callback)(void* userdata), void* userdata, S32 bottom_pad = 0); // pad below bottom row of buttons @@ -80,6 +82,8 @@ public: bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response); + void onEditButtonClick(); + static void onCheckLock(LLUICtrl*, void*); static void onHelpComboCommit(LLUICtrl* ctrl, void* userdata); static void onClickBack(void* userdata); @@ -114,6 +118,7 @@ private: LLTextEditor* mEditor; void (*mLoadCallback)(void* userdata); void (*mSaveCallback)(void* userdata, BOOL close_after_save); + void (*mEditCallback)(void* userdata); void (*mSearchReplaceCallback) (void* userdata); void* mUserdata; LLComboBox *mFunctions; @@ -179,6 +184,7 @@ protected: // Used to view and edit an LSL that is attached to an object. class LLLiveLSLEditor : public LLPreview { + friend class LLLiveLSLFile; public: LLLiveLSLEditor(const LLSD& key); ~LLLiveLSLEditor(); @@ -202,7 +208,10 @@ private: virtual void loadAsset(); void loadAsset(BOOL is_new); - void saveIfNeeded(); + void saveIfNeeded(bool sync = true); + void openExternalEditor(); + std::string getTmpFileName(); + bool writeToFile(const std::string& filename); void uploadAssetViaCaps(const std::string& url, const std::string& filename, const LLUUID& task_id, @@ -218,6 +227,7 @@ private: static void onSearchReplace(void* userdata); static void onLoad(void* userdata); static void onSave(void* userdata, BOOL close_after_save); + static void onEdit(void* userdata); static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, @@ -227,7 +237,7 @@ private: static void onRunningCheckboxClicked(LLUICtrl*, void* userdata); static void onReset(void* userdata); -// void loadScriptText(const std::string& filename); // unused + bool loadScriptText(const std::string& filename); void loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type); static void onErrorList(LLUICtrl*, void* user_data); @@ -253,6 +263,7 @@ private: LLCheckBoxCtrl* mMonoCheckbox; BOOL mIsModifiable; + LLLiveLSLFile* mLiveFile; }; #endif // LL_LLPREVIEWSCRIPT_H diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml index 1e332a40c2..a041c9b229 100644 --- a/indra/newview/skins/default/xui/en/panel_script_ed.xml +++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml @@ -179,4 +179,13 @@ right="487" name="Save_btn" width="81" /> +